zoukankan      html  css  js  c++  java
  • 跨域请求详解

    同源策略

    Ajax的一个限制是同源策略(same origin policy),它要求所有请求必须来自同一个域名、子域名,并且地址的端口也应当一致。主要原因是处于安全考虑:因为当一个ajax请示被发送,所有的请求都会附带主域的cookie信息一起发送。也就是说,对于远程服务来讲,请求如果是来自于登陆后的用户,若没有同源策略的限制,攻击者就有可能获取你的Gmail里的邮件、得到你的 Fackbook 状态或者你 Twitter 中的好友,这是一个非常严重的安全性问题。

    但是,尽管出于安全问题的考虑而提出了同源策略,这也对那些的确需要跨域获取合法数据的开发者造成了一些不方便。诸如Adobe Flash和JAVA之类的技术已经着手解决了这个问题,通常是使用跨域策略文件。现在针对Ajax,也提出了CORS(cross-origin resource sharing)的标准规范。

    CORS

    CORS打破同源策略的限制,赋予了前端代码访问可信的远程服务的权限。主流的浏览器都很好的支持这个规范,除非使用IE6,基本上可以很好地使用它。

    支持CORS的浏览器:

    • IE>=8(需要安全caveat)
    • Firefox>=3
    • Safari:完全支持
    • Chrome:完全支持
    • Opera:不支持

    CORS的使用非常简单。如果想将你的服务器添加为受信任的数据源,只需在HTTP协议的响应头里加几行:

    Access-Control-Allow-Origin:example.com

    Access-Control-Request-Method:GET,POST

    这两个头字段会对来自example.com的跨域GET和POST请求做验证。多个值之间用逗号分隔,就像上面提到的GET,POST值一样。如果要添加多个域名,将域名列在 Access-Control-Allow-Origin头字段之中,每两个域名之间用逗号分隔。如果允许来自任意域的访问请求,则需要在源中加入通配符(*)。

    对于有些浏览器,比如Safari,它会首先发起一个OPTIONS请求以检查服务器是否允许跨域的请求。

    另一方面,Firefox则会直接发起跨域请求,但当服务器没有配置CORS头字段时会抛出一个安全异常。需要注意一下这种浏览器行为的不同。

    你甚至可以使用 Access-Control-Allow-Headers头字段来认证自定义的请求头:

    Access-Control-Request-Headers:Authorization

    这也意味着客户端可以在Ajax请求中添加自定义头,比如使用开放认证(OAuth)对请求进行签名:

    var req=new XMLHttpRequest();

    req.open("POST","/endpoint",true);

    req.setRequestHeader("Authorization",oauth_signature);

    XDomainRequest

    不幸的是,尽管CORS是可以正常工作在IE8及更高版本的IE中的,微软还是选择另辟蹊径,不兼容规范且对W3C工作组制定的标准视而不见。微软使用了一个自己的对象XDomainRequest,用来代替XMLHttpRequest进行跨域通信。它的接口和XMLHttpRequest的非常像,它包含一系列约束和限制,比如只支持GET和POST方法,不支持验证和自定义字段,并且支持“Content-Type:text/plain"类型的请求。

    如果你满足来这些限制条件,就可以在IE8中使用正确的Access-Control头字段和XDomainRequest来实现CORS,网页可以直接在浏览器中生成跨域数据请求,而不必使用服务器到服务器的请求。跨域请求需要经过网页和服务器的相互同意。通过利用window对象创建XDomainRequest对象,并打开到特定域的连接,可以在网页中启动一个跨域请求。浏览器将通过发送带有源值的Origin请求头,从特定域的服务器中请求数据。如果服务器响应的Access-Control-Allow-Origin响应头为*或请求页面的确切URL,则浏览器将完成连接,然后可以使用XDomainRequest跨域请求目标服务器上的数据。XDomainRequest使用如下所示:

    // 1. Create XDR object: 
    var xdr = new XDomainRequest(); 
    
    // 2. Open connection with server using GET method:
    xdr.open("get", "http://www.contoso.com/xdr.aspx");
    
    // 3. Send string data to server:
    xdr.send();

    xdr.onload=function(){
    var data=JSON.parse(xdr.responseText);
    };

    XDomain支持的方法有onload,onerror,ontimeout,onprogress,timeout。

    JSONP

    JSONP(JSON with padding)很早之前就被标准化了,甚至在CORS之前。这是另一种从远程服务器抓取数据的方式。原理是通过创建一个script标签,所请求的外部文件包含一段JSON数据,数据是由服务器所返回的,作为参数包装在一个函数调用中。script标签获取脚本文件并不受跨域的限制,所有浏览器都支持这种技术。

    下面的例子是一个script标签指向一个远程服务:

    <script src="http://example.com/data.json"></script>

    所请求的文件data.json中包含一个JSON对象,这个对象包装在一个函数调用中:

    jsonCallback({"data":"foo"})

    这时我们定义一个全局函数,当加载脚本后,这个函数就会被调用:

    window.jsonCallback=function(result){

    //处理返回结果的相关逻辑

    }

    jQuery将这个过程包装成了简洁API:

    jQuery.getJSON("http://example.com/data.json?callback=jsonCallback",function(result){
    console.log(result);
    });

    或者

      $.ajax({  
            url:"http://crossdomain.com/services.php",  
            dataType:'jsonp',  
            data:'',  
            jsonp:'callback',  
            success:function(result) {  
            },  
            timeout:3000  
        }); 

    jQuery将上面的URL中最后的问号替换为一个由它创建的随机命名的临时函数。服务器会获取这个callback参数,使用这个名字作为回调函数名称返回给客户端。

     参考资料:

    《基于MVC的Javascript Web富应用开发》

    http://msdn.microsoft.com/zh-cn/library/dd573303%28v=vs.85%29.aspx

  • 相关阅读:
    ReentrantLock类详解
    Linux中 docker安装
    canvas画图练习教程
    Axure 9 使用笔记
    设计模式9—工厂模式【创建型】
    Docker 快速部署 MySQL
    Laravel Sanctum SPA cookie&session 验证实践
    地图地区生成随机点
    Laravel Class 'DoctrineDBALDriverPDOMySqlDriver' not found
    LightHouse 自定义参数指令 (Argument Directives)
  • 原文地址:https://www.cnblogs.com/linxuehan/p/3907462.html
Copyright © 2011-2022 走看看