【跨域】跨域的简易实现和测试

前言

因为本身平时只作作demo,并无遇到太多跨域问题,今天经过几个样例模拟实现了几种跨域方式。原文地址 传送门html

本文全部样例静态服务器基于nodejs实现,代码亲测可用。测试步骤以下:前端

1.为了实现跨域访问的效果,须要下载http-server 做为一个服务器 npm install http-server。用来挂载静态页面 index.html 。(访问http://127.0.0.1:8080 显示index.html页面)
2.运行node建立的静态服务器node server (node搭建静态服务向下翻)html5

JSONP跨域

JSONP实现跨域原理

说道跨域可能最早想到就时 jsonp ,实现原理为:同源策略只限制浏览器的行为而不限制js,因此能够将请求写到 script 标签中。关键代码以下:node

<script>
    function jsonpCallback(args){...}
</script>
<script src='http://127.0.0.1:3000?callback=jsonpCallback'></script>

前端发出跨域请求数据后,服务端去解析该请求:web

const data={...}
const callback = req.parse(req.url,true).query.callback
res.writeHead(200)

//最关键的一步,拼接回调函数和做为函数参数的数据data
res.end(`${callback}(${JSON.stringfy(data)})`)

浏览器接收到服务端返回的响应,因为发起请求的是script,至关于直接调用方法并传入参数ajax

具体实现案例

(服务端代码,node.js)npm

const url = require('url');

require('http').createServer((req, res) => {
    const data = {
        x: 10
    };
    const callback = url.parse(req.url, true).query.callback
    res.writeHead(200);
    //回调原页面上函数处理返回结果
    res.end(`${callback}(${JSON.stringify(data)})`);

}).listen(3000, '127.0.0.1');
console.log('服务器已启动...');

(前端)json

<!DOCTYPE html>
<html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
    </head>
    <body>
        <script>
            function jsonpCallback(data){
                alert('跨域成功')
            }   
        </script>
        <script src="http://127.0.0.1:3000/?callback=jsonpCallback"></script>
    </body>
</html>

JSONP解决Ajax跨域问题

若是是采用js原生,能够参考传送门segmentfault

CORS跨域

实现CORS跨域的思想为:CORS通讯和Ajax同源请求没有区别,关键在于服务端的配置。要想实现CORS通讯,服务端必需要设置一个自定义头Access-Control-Origin:''来容许跨域访问 后端

(样例仅作了一个最简单的GET请求demo服务端代码)

require('http').createServer((req,res)=>{
    res.writeHead(200,{
        'Access-Control-Allow-Origin':'http://127.0.0.1:8080'
    })
    res.end('这是来自端口3000的信息,收好了~')
}).listen(3000,'127.0.0.1')

(前端代码)

<!DOCTYPE html>
<html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    <script>
        //CORS通讯和同源ajax通讯没有区别,重点是子服务器端要设置能够容许跨域的自定义头
        const ajax = new XMLHttpRequest()
        ajax.open('post','http://127.0.0.1:3000',true) 
        ajax.onreadystatechange = function(){
            if(ajax.readyState===4){
                if(ajax.status>=200&&ajax.status<300||ajax.status===304){
                    alert(ajax.responseText)
                }
            }
        }
        ajax.send(null)
    </script>
</html>

cors实现跨域的优势是不但能实现 GET , POST 等简单请求,还能实现 PUT 等非简单请求跨域

ServerProxy服务器代理

ServerProxy服务器代理实现跨域的核心思想是:将跨域请求操做发送给服务端,由服务端代为请求,而后将请求结返回过来
这里以获取 CNode:Node.js专业中文社区 论坛上一些数据为场景。如经过 https://cnodejs.org/api/v1/to...,当时由于不一样域,因此你能够将请求后端,让其对该请求代为转发。

const url = require('url')
const http = require('http')
const https = require('https')

const server = http.createServer((req,res)=>{
    const path = url.parse(req.url).path.slice(1)
    if(path==='topics'){
        https.get('https://cnodejs.org/api/v1/topics', (resp) => {
            let data=''
            resp.on('data',chunk=>{
                data+=chunk
            })
            resp.on('end',()=>{
                res.writeHead(200,{
                    'Content-Type':'application/json;charset=utf-8'
                })
                res.end(data)
            })
        })
    }
}).listen(3000,'127.0.0.1')

console.log('服务器已启动...');

postMessage

postMessage是HTML5新增的一项功能,postMessage() 方法容许来自不一样源的脚本采用异步方式进行有限通讯能够实现跨文本文档,多窗口,跨域消息传递。
利用postMessage不能和服务端交换数据,只能在两个窗口 <iframe> 之间交换数据

postMessage(data,origin)方法接收两个参数
data:html5规范中提到该参数能够是JavaScript的任意基本类型或可复制的对象.然而并非全部浏览器都作到了这点儿,部分浏览器只能处理字符串参数,因此咱们在传递参数的时候须要使用JSON.stringify()方法对对象参数序列化
oringin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略。这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,固然若是愿意也能够建参数设置为"*",这样能够传递给任意窗口,若是要指定和当前窗口同源的话设置为"/"

建立一个postMsg.html,建立一个iframe。使用postMessage能够向 http://127.0.0.1:8081 发送消息,而后监听 message ,能够得到其余文档发来的消息

<!DOCTYPE html>
<html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
    </head>
    <body>
        <iframe src="http://127.0.0.1:8081/recieve.html" style="display:none;"></iframe>
        <script>
            window.onload = function(){
                let targetOrigin='http://127.0.0.1:8081'
                window.frames[0].postMessage('我要给你发消息了..!',targetOrigin)
            }
            window.addEventListener('message',function(e){
                console.log('postMsg.html 接收到的消息',e.data)
            })
        </script>
    </body>
</html>

(建立recieve.html文件)

<!DOCTYPE html>
<html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
    </head>
    <body>
        <script>
            window.addEventListener('message',function(e){
                if(e.source!=window.parent){
                    return
                }
                let data = e.data
                console.log('test.html 接收到的消息:',data)
                parent.postMessage('我已经接收到消息了!',e.origin)
            })
        </script>
    </body>
</html>

安全性: postMessage 采用的是 双向安全机制 。发送方发送数据时,会确认接收方的源,而监听方监听到 message 事件后,也能够用 event.origin 判断是否来自于正确可靠的发送方

webSocket实现跨域

websocket是一中全双工通讯协议,该协议不实行同源政策,只要服务器支持,就能够经过它进行跨源通讯
websocket的应用实例:https://segmentfault.com/a/11...

document.domain

对于主域相同跨子域的状况,能够经过设置 document.domain 来解决。具体作法是在 example.com/a.html 和 sub.example.com/b.html 两个文件分别加上 document.domain = example.com 而后经过a.html 文件建立一个iframe,去控制iframe的 window,从而进行交互

相关文章
相关标签/搜索