前端跨域详解

同源策略

同源策略(Same Origin Policy)是浏览器最核心也是最基本的安全功能。浏览器的同源策略,限制了来自其他源的document或脚本,读写当前document的属性。如果没有同源策略,来自A.com的脚本,可以在B.com未曾加载此脚本时,也可以在浏览器显示中随意涂改B.com的页面,这将带来严重的安全问题。

判断脚本的源

决定是否同源的因素有:host,子域名,端口,协议。
在判断一段脚本的源需要注意的是,不是判断存放脚本的域,而是判断该脚本加载的域,例如

  <script src="http://B.com/b.js"></script>

此时这段脚本在A.com上加载运行,那么这段脚本的源是A.com而不是B.com。

通过document.domain跨域

不同的框架之间是可以获取window对象的,但却无法获取相应的属性和方法。比如,有一个页面,它的地址是www.example.cn/a.html , 在这个页面里面有一个iframe,它的src是example.cn/b.html, 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的.
这个时候,document.domain就可以派上用场了,我们只要把www.example.cn/a.html 和 example.cn/b.html 这两个页面的document.domain都设成相同的域名就可以了。但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。

    <iframe id = "iframe" src="http://example.cn/b.html" onload = "test()"></iframe>
    <script type="text/javascript">
        document.domain = 'example.cn';//设置成主域
        function test(){        alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象
        }
    </script>

修改document.domain的方法只适用于不同子域的框架间的交互

JSONP跨域

在浏览器中,<script><iframe>img<link> 等标签都可以跨域加载。这些带src属性的标签每次加载时,实际上是由浏览器发起了一次GET请求。关于JSONP跨域可以参考我另一篇博文 前端脚本化http

postMessage跨域

H5在IE8以上浏览器开始支持postMessagepostMessage 允许每一个window 对象往其他窗口发送文本消息,从而实现跨窗口的消息传递,这个功能不受同源策略限制。
postMessage 实现核心在于约定,在一个窗口中使用postMessage方法,另一个窗口对message 事件进行监听。在接受窗口可以验证Domain和URL,以防止非法页面的消息。

Web Storage

Web Storage API 同样遵守同源策略。

CORS服务器端

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
如何在服务器端做配置来允许跨域传输呢?下面以Nginx为例讲一下配置。

    Access-Control-Allow-Origin(必含) – 允许的域名,只能填通配符或者单域名

Access-Control-Allow-Methods(必含) – 这允许跨域请求的http方法(常见有POST、GET、OPTIONS)
Access-Control-Allow-Headers(当预请求中包含Access-Control-Request-Headers时必须包含) – 这是对预请求当中Access-Control-Request-Headers的回复,和上面一样是以逗号分隔的列表,可以返回所有支持的头部。
Access-Control-Allow-Credentials(可选) – 该项标志着CORS请求当中是否包含cookies信息,只有一个可选值:true(必为小写)。如果不包含cookies,请略去该项,而不是填写false。这一项与XmlHttpRequest2对象当中的withCredentials属性应保持一致,即withCredentials为true时该项也为true;withCredentials为false时,省略该项不写。反之则导致请求失败。
Access-Control-Max-Age(可选) – 以秒为单位的缓存时间。预请求的的发送并非免费午餐,允许时应当尽可能缓存。
具体配置举例:
打开Nginx的配置文件(默认为nginx.conf)。找到对应域名设置的local配置部分。
添加以下内容:

    add_header 'Access-Control-Allow-origin' 'http://www.example.com';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

如果允许跨域的域名有多个但出于安全问题又不想配置全域名通配的时候,就可以用到nginx里的if判断了。(或者正则)
添加如下内容:

    if ($http_origin = 'http://sysuzhyupeng.com' ) {  
        add_header 'Access-Control-Allow-Origin' "$http_origin";
        if ($request_method = "OPTIONS") {
            add_header 'Access-Control-Max-Age' 86400;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE';
            add_header 'Access-Control-Allow-Headers' 'reqid, nid, host, x-real-ip, x-forwarded-ip, event-type, event-id, accept, content-type';
            add_header 'Content-Length' 0;
            add_header 'Content-Type' 'text/plain, charset=utf-8';
            return 204;
        }
     }

CORS客户端

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时满足以下两大条件,就属于简单请求。
(1) 请求方法是以下三种方法之一:

  • HEAD
  • GET
  • POST

(2)HTTP的头信息不超出以下几种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

凡是不同时满足上面两个条件,就属于非简单请求。浏览器对这两种请求的处理,是不一样的。对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。”预检”请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。如果服务器返回的头信息中的Access-Control-Allow-Origin包括Origin,浏览器才会发送真实的请求。一旦服务器通过了”预检”请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。
上面说到,CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段

    Access-Control-Allow-Credentials: true

另一方面,开发者必须在AJAX请求中打开withCredentials属性。

    var xhr = new XMLHttpRequest();
    xhr.withCredentials = true;

如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号(允许全部),必须指定明确的、与请求网页一致的域名。原网页代码中的document.cookie无法读取服务器域名下的Cookie。
CORS与JSONP的使用目的相同,但是比JSONP更强大。JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值