美文网首页
跨域原理

跨域原理

作者: 饥人谷1904_陈俊锋 | 来源:发表于2019-07-11 14:34 被阅读0次

    跨域:浏览器对于javascript的同源策略的限制,例如a.com下面的js不能调用b.com中的js,对象或数据(因为a.com和b.com是不同域),所以跨域就出现了。

    同源策略:浏览器施加的安全限制,请求的url地址,必须与浏览器上的url地址处于同域上,也就是协议,域名和端口都相同。

    通过ajax去向a.com:8080发请求 此时当前页面与请求端同域:获取数据成功 如果当前页面与请求端不同源(跨域):无法读写对方的资源

    需要注意的是:对于当前页面来说页面存放的JS文件的域不重要,重要的是加载该JS页面所在什么域

    那么下面我们开始探讨跨域的一些方式以及原理

    1.JSONP

    首先我们需要知道的是 HTML 中 script 标签可以加载其他域下的js,比如我们经常引入一个其他域下线上cdn的jQuery。

    因此 可以利用这个特性实现从其他域下获取数据。

    <script src="http://api.data.com/getInfo.php"></script>
    

    这里我们会有一个疑问:我们向其他域数据接口发送请求,获取数据后作为 js 来执行,但是这里的数据是 JSON 格式的数据,如果直接作为 js 运行的话我们应该如何去得到这个数据,进而进行我们想要的操作呢?

    <script src="http://api.data.com/getInfo.php?callback=showData"></script>
    

    这个请求到达后端后,后端会去解析callback这个参数获取到字符串showData,在发送数据时做如下的处理:

    之前后端返回的数据是:{ "info": "something" },现在返回的数据是:showData({ "info": "something" }),前端script标签在加载数据后会把 「 showData({ "info": "something" }) 」当作js来执行,实际上就是调用了showData函数,此时参数是 { "info": "something" }。用户只需要提前在页面定义好showData这个全局函数,在函数内部处理参数即可。

    <script>
    function showData(ret){
      ...
    }
    </script>
    <script src="http://api.data.com/getInfo.php?callback=showData"></script>
    

    所以总结来说JSONP是通过 script 标签加载数据的方式去获取数据当做 JS 代码来执行 提前在页面上声明一个函数,函数名通过接口传参的方式传给后台,后台解析到函数名后在原始数据上「包裹」这个函数名,发送给前端。换句话说,JSONP 需要对应接口的后端的配合才能实现。

    下面我们来演示一下:

    请求端代码
    同源获取数据 no problem
    跨域获取数据 一样也是 no problem
    当前页面通过添加script标签,向数据接口页面发送请求获取数据并当作 提前在当前页面声明好的一个函数的参数 去执行并操作数据。

    2. CORS

    跨域资源共享(Cross-Origin Resource Sharing),是一种ajax跨域请求资源的方式,支持现代浏览器,IE10以上。

    实现方式:当你使用 XMLHttpRequest 发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin; 浏览器判断该响应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。

    CORS 的表象是让你觉得它与同源的 ajax 请求没啥区别,代码完全一样。

    页面直接使用ajax发送请求


    请求端

    后端服务器发送响应时加上一个响应头


    server.js

    其中,res.setHeader('Access-Control-Allow-Origin','http://localhost:8080') 指的是后端允许的域名是 localhost: 8080;而 res.setHeader('Access-Control-Allow-Origin', '*') 则是允许任何人获取数据。

    下面我们来演示一下(任何人都可以获取数据的情况):

    同域


    向a.com: 8080发送请求 在本域内

    下面的截图显示的是 允许域名是 http://localhost: 8080 的用户跨域获取数据

    域名是http://localhost: 8080

    跨域


    不同源也没有获得允许
    同上

    3. 降域

    场景:当前页面存在/嵌套不同域的iframe

    只有在相同域名的条件下,才能去访问iframe里面的东西
    不同域名的条件下,iframe里面的东西可以被加载但是不能获取和被操作

    阻止跨域使用frame,无法实现跨域操作 同域允许操作iframe 利用document.domain降域之后彼此可以相互访问
    document.domain = 'jrg.com' 在两者中把二者降到 'jrg.com' 主域下,使二者之间可以实现相互访问
    前提是 域名要有相同的末尾段主域可降

    4. postMessage

    没有主域限制

    嵌套跨域 iframe 的页面

    // 当需要对iframe进行一定操作时
    // 向当前iframe postMessage一个消息
    // * 表示任何域下都可以接受
    window.frames[0].postMessage(this.value,'*');
    

    被嵌套的 iframe 本域的页面/接口

    // 监听message事件(从中知道是否有人嵌套了本地iframe并向本地发送了消息)获取了消息数据并做对应的事情
    // 可以定义出一些接口告知嵌套方要操作iframe可以发送消息
    // 本地内部对消息有一些实现(通过嵌套方发送消息来修改一些东西)
    window.addEventListener('message',function(e) {
        $('.main input').value = e.data
        console.log('b get:' + e.data);
    });
    

    首先,aa.html可以向bb.html postMessage消息


    aa.html

    bb.html监听到message消息做出对应的事情


    bb.html
    简单的postMessage演示

    参考 饥人谷 / 跨域

    相关文章

      网友评论

          本文标题:跨域原理

          本文链接:https://www.haomeiwen.com/subject/svcrkctx.html