• 同源策略和跨域问题


    1.同源策略

      指浏览器对不同源的脚本或者文本的访问方式进行的限制。比如源a的js不能引入源b的元素属性。

      所谓的同源是指两个页面具有相同的协议、主机(也是常说的域名)、端口,三个元素缺一不可。

      通过下列示例具体了解一下同源:

        

      同源策略限制了不同源之间的交互,(同源策略限制了不同源之间的交互主要针对js中的XMLHttpRequest等请求)下面这些情况完全不受同源策略的限制的。

        1.页面中的链接,重定向以及表单提交是不会受同源策略的影响。(在你的域名www.foo.com下面提交一个表单到www.bar.com是完全可以的)

        2.跨域资源嵌入是允许的,如果浏览器限制了JavaScript,就不能读写加载的内容。(如前面提到的嵌入的<script src="..."></script>,<img>,<link>,<iframe>等),当然,如果要阻止iframe

         嵌入我们的网站资源时(页面或者js等),我们可以在web既然有这么多的情况是没有同源策略限制的,那么跨域问题是怎么来的?

    2.跨域问题

      前置条件是我们在web服务器或者服务端脚本中设置ACCESS-CONTROL-ALLOW-ORIGIN头部,如果设置了这些头部并且允许某些域名跨域访问,则浏览器就会跳过同源策略的限制返回对应的内容。此外,如果你不是通过浏览器

      获取资源,比如你通过一个Python脚本调用接口或者获取js文件,也不在这个限制范围之内。

      1.AJAX跨域

        通过AJAX调用其它域的接口会有跨域问题。比如:我在http://www.foo.com/index.html中通过ajax调用请求http://www.bar.com/js/test.js页面,此时是会报错的。

          XMLHttpRequest cannot load http://www.bar.com/js/test.js. 

          No 'Access-Control-Allow-Origin' header is present on the requested resource. 

          Origin 'http://www.foo.com' is therefore not allowed access.

        这是因为我们的WEB服务器没有设置ACCESS-CONTROL-ALLOW-ORIGIN头部,默认情况下是禁止跨域引用资源的。当然这里有一点要注意,其实这个跨域请求是发送成功了的,服务器也有返回test.js内容,只是浏览器禁止

        Javascript去取response的数据而已。如果要设置ACCESS-CONTROL-ALLOW-ORIGIN头部,nginx可以使用下面的代码

          add_header 'Access-Control-Allow-Origin' 'http://www.foo.com';

           add_header 'Access-Control-Allow-Credentials' 'true';

          add_header 'Access-Control-Allow-Methods' 'GET,POST';

        另外,我们看到直接通过Javascript去取iframe中的元素也是会报错的,因为域名不同。报错如下所示

          Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://www.foo.com" from accessing a frame with origin "http://foo.com". 

          The frame being accessed set "document.domain" to "foo.com", but the frame requesting access did not. Both must set "document.domain" to the same value to allow access.

        这时因为我们的主域名相同,因此可以在index.html和test.html中设置document.domain='foo.com'来访问iframe中的元素。注意,是两个域名下面的文件都要设置,即便是同样的主域名。当然这是特例,如果是两个完全不同

        的域名,是没有办法的,你不能把www.foo.comdomain设置成www.163.com

        此外,在index.html里面也可以看到通过<script>,<iframe>等标签都是可以跨域内嵌资源的。

          # index.html

          <!DOCTYPE html>
          <html>
          <head>
          <title>test cross domain</title>
          <script src="/js/jquery.js"></script>
          <script src="http://www.bar.com/js/test.js"></script>
          <script>
          $(function(){
              document.domain = 'foo.com'; //1 注释掉则会报错 
              var ifr = document.getElementById("testframe");
              ifr.onload = function(){
                  var doc = ifr.contentDocument || ifr.contentWindow.document;
                  alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);
              }
          });
    
          $.ajax("http://www.bar.com/js/test.js"); //2 报错
          </script>
    
          </head>
          <body>
          <h1>Test Cross Domain</h1>
          <iframe id="testframe" src="http://foo.com/test.html"></iframe>
          </body>
          </html>
      
    当然还可以通过iframe,location.hash,window.name,HTML5的postMessage等方法来实现跨域资源访问
     2.JSONP跨域访问(JSON+padding)
    创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调 将JSON数据填充进回调函数
       JSONP也是在开发中常见的内容,在jQuery中有封装,通过ajax请求多带上一个jsonp参数即可。JSONP也能够实现跨域访问资源。但是它的实现原理跟ajax没有多大关系,它是通过动态插入<script>
       标签来实现资源访问的,在实际jsonp接口中,会让你传一个函数名过去,然后返回的数据中回调函数名就是你传的函数名,回调函数的参数就是你封装的jsonp格式,jQuery中的jsonp实现原理
       基本上就是这样实现的。
          
    # jsonp.html
          <script type="text/javascript">
              function callback(data) {
                  alert(data.message);
              }
              function addScriptTag(src){
              var script = document.createElement('script');
                  script.src = src;
                  document.body.appendChild(script);
              }
    
              window.onload = function(){
                 addScriptTag("http://www.foo.com/js/outer.js");
              }
          </script>
    
          # outer.js
          callback({message:"success"});










  • 相关阅读:
    KMP 算法 C++
    java RTTI笔记 之Class学习笔记(摘自java编程思想)
    java sql
    event
    mysql 编写存储过程
    《淘宝技术这十年》重读笔记
    关于“产品”的笔记
    程序员,当你遇到一个“坑”
    C盘清理大作战
    android开发笔记
  • 原文地址:https://www.cnblogs.com/jacky912/p/10469675.html
Copyright © 2020-2023  润新知