天天看点

跨域资源共享CORS以及在zepto中使用遇到的问题

            跨域资源共享CORS以及在zepto中使用遇到的问题

一、 跨域资源共享CORS

     1.浏览器的同源策略

        同源策略在web应用的安全模型中是一个重要概念。在这个策略下,web浏览器允许第一个页面的脚本访问第二个页面里的数据,但是也只有在两个页面有相同的源时。源是由URI,主机名,端口号组合而成的。这个策略可以阻止一个页面上的恶意脚本通过页面的DOM对象获得访问另一个页面上敏感信息的权限。

        当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。出于安全考虑,浏览器会限制从脚本内发起的跨域HTTP请求。例如,XMLHttpRequest 和 Fetch 遵循同源策略。因此,使用 XMLHttpRequest或 Fetch 的Web应用程序只能将HTTP请求发送到其自己的域。

     2.跨域资源共享( CORS )

      CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制

      CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

     3.怎么实现CORS

         现在有一个需求是:A.test.com域下的js请求B.test.com的C接口,并且C接口完成相关的功能并往".test.com"写cookie

         首先是跨域且跨域(严格意义是跨域,虽然是往".test.com"写cookie)写cookie

         代码实现:

                 A.test.com域下的js代码:              

$.ajax({
            type:'post',
            data:{'param':"hello"},
            cache:false,
            url:"https://B.test.com/hello",
            xhrFields: {withCredentials: true},
            success:function(result){
                alert("success hello result="+result)

            }
            ,error:function(XMLHttpRequest, textStatus, errorThrown){
                alert("error XMLHttpRequest="+XMLHttpRequest+";textStatus="+textStatus);
            }
        });
           

      其中withCredentials: true是指跨域请求带上cookies

       B.test.com的C接口支持跨域的代码:         

beat().getResponse().setHeader("Access-Control-Allow-Origin", "https://A.test.com");//*表示任何域名都可以提交过来,如果加上域名则表示只允许某个域名提交
        beat().getResponse().setHeader("Access-Control-Allow-Methods", "POST,GET");
        beat().getResponse().setHeader("Access-Control-Allow-Credentials", "true");
           

        其中,Access-Control-Allow-Origin该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

        Access-Control-Allow-Credentials该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段的值为true。

     4.CORS与JSONP相比,更为先进、方便和可靠。

      1)JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。

      2)使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。

      3)JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS。 对一个简单的请求,没有自定义头部,要么使用GET,要么使用POST,它的主体是text/plain,请求用一个名叫Orgin的额外的头部发送。Origin头部包含请求页面的头部(协议,域名,端口),这样服务器可以很容易的决定它是否应该提供响应。 

  二、在zepto中使用CORS遇到的问题          

         现在移动 Web 开发中,Zepto.js 是使用频率比较高的库之一。由于它的体积小,加载速度快,有着和 jquery 类似的 API,而备受开发者喜爱。移动端上面使用 zepto.js, 通过 Fiddler 或 Charles 抓包发现,在 webview 中,点击按钮之后的 Ajax 请求并未发出,但是页面在手机QQ浏览器和 PC 上表现都是正常的。绝大多数手机是ok的,但是在 Android 的 webview 和一些旧版本的手机浏览器中会抛出错误(zepto.js的版本是v1.1.6),如oppo手机,4.3的系统ajax请求发不出去

     原因是zepto.js中 :由于一些老版本的浏览器是按照 2012 年之前的规范来实现的,所以这一部分浏览器中,open() 方法要在设置 withCredentials 属性之前调用。因此为了兼容,正确的做法应该是在 open() 方法之后再设置 withCredentials 属性。      正确代码如下:

跨域资源共享CORS以及在zepto中使用遇到的问题

   总结:在使用 CORS 时,如果要给 withCredentials 赋值,请务必要在 open() 方法之后,否则无法向后兼容。Zepto v1.2.0(http://zeptojs.com/zepto.js)已经是: withCredentials 赋值在 open() 方法之后