1.为什么要跨域

同源策略限制一个源加载的文档或文档与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的安全机制。
什么是同源呢? 如果协议,端口(如果指定了一个)和域名对于两个页面是相同的,则两个页面具有相同的源。
下表给出了相对http://store.company.com/dir/...同源检测的示例:
clipboard.png

跨域网络访问通常分为3种

  • 通常允许进行跨域写操作(Cross-origin writes)。例如链接(links),重定向以及表单提交。特定少数的HTTP请求需要添加 preflight。

  • 通常允许跨域资源嵌入(Cross-origin embedding)。

  • 通常不允许跨域读操作(Cross-origin reads)。但常可以通过内嵌资源来巧妙的进行读取访问。例如可以读取嵌入图片的高度和宽度,调用内嵌脚本的方法。
    另外,同源策略约束了XMLHttpRequest,也就是说ajax进行跨域访问会报错。

2.跨域的解决方式

2.1 window.name

原理: 再浏览器中打开一个页面中,或用iframe打开一个页面时会创建一个window对象,当页面加载一个新的页面时,window.name属性是不会变的,因此我们可以在页面中动态创建一个iframe页面指向另一个域,将数据赋值个window.name属性。(值得注意的是,此时我们无法直接访问window.name),我们还需要将将iframe的src指向相同域的空白页面。之后再将iframe删除就可以了

//http://localhost:3000/request.js
     function CreateIframe(src, nextsrc){
        var iframe = document.createElement('iframe');
        var flag = true;
        iframe.src = src;
        iframe.style.display = 'none';
        iframe.onload = function(){
            if(flag){
                iframe.src = nextsrc;
                flag = false;
            }else{
                p.innerHTML = iframe.contentWindow.name;
                iframe.contentWindow.close();
                document.body.removeChild(iframe);
                iframe.src = '';
                iframe = null
            };
        };
        document.body.appendChild(iframe);
    }

 CreateIframe('http://localhost:3001/a.html', 'http://localhost:3000/b.html');
//http://localhost:3001/response.js
        function ajax(url, method){
            const xhr = new XMLHttpRequest();
            xhr.onload = function(data){
                 window.name = this.responseText
                 console.log(window.name);
            }
            xhr.open(method, url, true);
            xhr.send(null);
        }
        ajax('http://localhost:3001/req', 'GET');
2.2 document_domain

原理:通过该document.domain来设置域名,但是有局限性,也就是一级域名一致才可以。

//http://localhost:3000/request.js
 document.domain = 'http://localhost:3001';
 document.getElementById('iframe').onload = function(){
      var win = iframe.contentWindow;
      var doc = win.document;
      console.log(win.data);
 }
//http://localhost:3001/response.js
        document.domain = 'http://localhost:3001';
        var data = '123';
2.3 JSONP

原理: JSONP实现跨域请求的原理简单的说,就是动态创建<script>标签,然后利用<script>的src 不受同源策略约束来跨域获取数据。

//index.html
    <script src="./jsonp.js"></script>
    <script>
        function myFunction (data) {
            console.log(data.message);
        }
        
        Jsonp('http://localhost:3001', 'myFunction');
    </script>
//jsonp.js
const Jsonp = (() => {
    function jsonp(url, handle){
        let script = document.createElement('script');
        script.setAttribute('src', `${url}?callback=${handle}`);
        document.body.appendChild(script);
    }
    return jsonp;
})()
//server.js
app.get('/', function (req, res) {
    var callbackName = req.query.callback;   // myFunction
    res.send(callbackName+"({'message': 'It is JSONP!'});");
})
2.4 HTML5PostMessage

PostMessage是HTML5的API,postMessage() 方法被调用时,会在所有页面脚本执行完毕之后向目标窗口派发一个 MessageEvent 消息。 该MessageEvent消息有四个属性需要注意: message 属性表示该message 的类型; data 属性为 window.postMessage 的第一个参数;origin 属性表示调用window.postMessage() 方法时调用页面的当前状态; source 属性记录调用 window.postMessage() 方法的窗口信息。
只有通过其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。才能使用

////http://localhost:3000/request.js
    var popup =window.open('http://localhost:3001/index4.html');
        function receive(event){
            if(event.origin !== 'http://localhost:3001') return;
            document.querySelector('#message').innerHTML = event.data;
        }
        window.addEventListener('message', receive, false);
//http://localhost:3001/response.js
    var popup = window.opener;
        popup.postMessage('发送消息', 'http://localhost:3000/');
        window.addEventListener('message', (e) => {
            if(e.origin !== 'http://localhost:3001') return;
            document.querySelector('#message').innerHTML = e.data;
            //e.source.postMessage('发送消息', e.origin);
        }, false)
2.4 CORS

cors主要靠服务器,只要服务器实现了cors接口,就可以跨源通信。具体的原理可以看阮老师的文章跨域资源共享 CORS 详解


殇柒
116 声望4 粉丝

前端小白