同源战略和跨域知识点进修

题目原由是在运用weibo api的时刻,发明有一个报错。weibo api是https协定,我当地是模仿的回调域名,然后举行数据通信,当地http协定,因而乎就报错了。出于对postMessage的不是很熟习,借此机会进修晚上一些本身的学问贮备。

api.weibo.com/2/oauth2/authorize?client_id=******&response_type=token&d…ansport=html5&referer=http://www.unofficial.cn/demo/vuejs/demo.html:1 Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://www.unofficial.cn') does not match the recipient window's origin ('http://www.unofficial.cn').

同源战略

在这之前须要先熟习一下这个观点,同源指要求协定雷同,主机名雷同,端口雷同,触及平安的战略。

    // 比方我的博客地点
    http://www.unofficial.cn/demo/postMessage/pm1.html      同
    http://www.unofficial.cn/demo/vuejs/index.html          同
    https://www.unofficial.cn/demo/postMessage/pm1.html     差别 协定差别
    http://blog.unofficial.cn/demo/postMessage/pm1.html     差别 主机名差别
    http://www.unofficial.cn:8080/demo/postMessage/pm1.html 差别 端口差别

许可跨域写

表单提交,比方我模仿了一个表单提交到我的一个别的站点。

同源战略主要限定的是差别源之间的交互操纵,关于跨域内嵌的资本不受该战略限定。

许可跨域嵌入

  • <script src=”……”></script> 标签嵌入剧本,语法毛病信息只能在同源剧本中捕捉到(?)。

  • <link rel=”stylesheet” href=”……”> 标签嵌入css

  • <img src=”” alt=””> 标签嵌入图片

  • <video></video> 和 <audio></audio> 标签嵌入多媒体资本

  • @font-face

  • <iframe src=”……” frameborder=”0″></iframe> 载入的任何资本。能够运用x-frame-options音讯头来阻挠这类情势的交互。

不许可跨域读

须要注重的是,页面内的引入的文件的域并不主要,主要的是加载该文件的页面地点的域。比方说我在博客的首页引入了 //cdn.bootcss.com/jquery/3.1.1/jquery.min.js 的jquery文件,这时候 jquery.min.js 的源应当就是我的博客地点 http://www.unofficial.cn

  • iframe
    同域可读可写,跨域可读不可写

// 要求地点://www.unofficial.cn/demo/postmessage/pm2.html
<iframe src="pm2.html" frameborder="0"></iframe>
<iframe src="//blog.unofficial.cn/demo/postmessage/pm2.html" frameborder="0"></iframe>
<script>
    window.onload = function() { // 必需守候文档加载完毕才猎取
        var iframe = document.getElementsByTagName('iframe');
        console.log(iframe[0].contentDocument); // 同源
        console.log(iframe[1].contentDocument); // 差别源
    }
</script>
// 差别源时运用contentWindow/contentDocument报错
// pm1.html:12 Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://www.unofficial.cn" from accessing a cross-origin frame.(…)
  • 同源

    iframe外部操纵,主要经由过程contentDocument/contentWindow,iframe内部运用window.parent,假如只是嵌套了一层能够运用window.top,iframe多层嵌套能够运用window.frameElement

        // 外部 -> 内
    
        var iframe = document.getElementsByTagName('iframe');
        // 举例第一个
        iframe[0].contentDocument.getElementById('test').innerText = 123;
    
        // 内部 -> 外
        window.parent.getElementById('test').innerText = 123;
  • 跨域

    假如须要在跨域的情况下通报参数怎样操纵呢?
    iframe内部操纵,主要经由过程 location.hash

        // 外部通报一个123给内部
        var src = iframe[0].src;
        iframe[0].src = src.indexOf('#') != -1 ? src.split('#')[0].concat('#', 123) : src.concat('#', 123);
        // 然后内部监测hashChange,自动猎取hash值
    
        // 内部变动hash
        window.location.hash = 123;
        // 然则怎样外部怎样监控src的变化呢?
  • ajax

    • cors

      同域可读可写,跨域要求不能检查到 Access-Control-Allow-Origin 的情况下会被阻拦。  
      // www.unofficial.cn:4000
      // 跨域要求
      var url = "http://www.unofficial.cn/demo.php";
      var params = "lorem=ipsum&name=binny";
      
      var http = new XMLHttpRequest();
      http.open("POST", url, true);
      
      http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
      
      http.onreadystatechange = function() {
      if(http.readyState == 4 && http.status == 200) {
          alert(http.responseText);
      }
      }
      http.send(params);
      > XMLHttpRequest cannot load http://www.unofficial.cn/demo.php. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://www.unofficial.cn:4000' is therefore not allowed access.
      
      上面毛病提醒能够设置 `Access-Control-Allow-Origin` ,因而在header中增加设置即可完成跨域要求。  
      
  • 参数引见

    • Access-Control-Allow-Origin
      origin参数指定一个许可向该服务器提交要求的URI.关于一个不带有credentials的要求,能够指定为’*’,示意许可来自一切域的要求.

    Access-Control-Allow-Origin: http://www.unofficial.cn
    • Access-Control-Allow-Credentials
      它的值是一个布尔值,示意是不是许可发送Cookie。默许是 true 许可的。 『现实测试没发明,也许是要领还不对吧。』

    • Access-Control-Expose-Headers
      设置浏览器许可接见的服务器的头信息的白名单。假如没有设置白名单的,默许情况下只能猎取 Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma的值,没设置返回 null,不然会获得以下提醒:

    Refused to get unsafe header “X-Powered-By”

    比方:

    // 服务端设置
    Access-Control-Expose-Headers: X-Powered-By

    前端能够如许猎取到 X-Powered-By 的属性值

        var http = new XMLHttpRequest();
    
        http.getResponseHeader('X-Powered-By'); // 
    • Access-Control-Max-Age
      设置预要求时候。等于设置 OPTION 的时候。

    • Access-Control-Allow-Methods
      设置许可的要求要领。

jsonp

cors的体式格局能够提议post要求,或许说别的情势的要求,然则jsonp只能运用get的体式格局猎取数据。

<script>
    function abc(data) {
        console.log(data);
    }abc('{"abc":"123"}');
</script>

<script src="http://www.unofficial.cn/test/demo.php?callback=abc"></script>

简单说就是定义好回调处置惩罚要领,把回调函数的称号通报给后端,后端拿到数据称号后返回会的数据就是关于回调要领的实行。

<script src="http://www.unofficial.cn/test/demo.js"></script>
/**
 * demo.js的内容
 * abc({"abc":"123"});
 */

什么是postMessage

postMessage是window对象的一个属性,widow.postMessage是一个平安的跨源通信协定。当且仅当实行剧本的页面运用雷同的协定(一般都是 http)、雷同的端口(http默许运用80端口)和雷同的 host(两个页面的 document.domain 的值雷同)时,才许可差别页面上的剧本相互接见。 window.postMessage 供应了一个可控的机制来平安地绕过这一限定,当其在准确运用的情况下。

  • iframe的情况下我们能够如许运用,守候页面加载完毕时传参数到指定源。

// localhost ① pm1.html页面中存在一个跨域iframe援用
<iframe src="//www.unofficial.com/demo/postMessage/pm2.html" frameborder="0"></iframe>
<script>
    window.onload = function() {
        window.frames[0].postMessage('some messages', '*'); // * 跨域是牢固的targetOrigin(必需指明协定、主机名、端口) http://www.unofficial.com
    }
</script>

// www.unofficial.cn pm2.html中我们跨域监听 `message` 猎取 `postmessage` 传过来的数据。  
<script>
    window.addEventListener('message', function(event) {
        if(event.origin.test('//localhost/')) {
            console.log(event.data);
        }
    })
</script>
  • window.open的情况下就须要特别处置惩罚一下了

// localhost ② window.open
<script>
    function openAPage() {
        // 同源的情况下能够推断页面是不是加载完毕
        var openPage = window.open('//localhost/demo/postMessage/pm2.html');
        openPage.onload = function() {
            openPage.postMessage('some messages', '*');
        }
        // 差别源的情况下,运用setTimeout或许setInterval
        var openPage = window.open('//www.unofficial.com/demo/postMessage/pm2.html');
        setTimeout(function() {
            openPage.postMessage('some messages', '*');
        }, 0)
    }
</script>

耽误多长时候实行?页面加载时候是多长,这个不是很好推断,setTimeout须要略预计一个时候,待open的页面加载完成了再postMessage(应当不比完整加载就能够postMessage了)。要不然就是定时器,定时推一次,直接触发事宜后运用window.opener作废定时器。

总结

题目基础都是在过程当中发明一个进修一个,关于没有太多场景的进修,只能如许逐步积聚。

参考资料

点赞