美文网首页
HTTP访问控制(CORS)

HTTP访问控制(CORS)

作者: Yvan_Yang | 来源:发表于2016-04-17 20:10 被阅读0次

    在Web开发中,经常会碰到跨站请求。比如A域名下的站点http://domainA通过AJAX请求B域名下的站点http://domainB的资源(比如图片,javascript脚本或其它类资源)。

    出于安全考虑,浏览器会限制脚本中发起的跨站请求。比如,使用XMLHttpRequest对象发起的HTTP请求就必须遵循同源策略。即Web应用程序只能使用XMLHttpRequest对象向其加载的源域名发起HTTP请求,而不能向任何其它域名发起请求。

    跨源资源共享(Cross-Orgin Resource Sharing(CORS))机制让Web应用服务器能支持跨站访问,从而使得安全的进行跨站数据传输成为可能。
    CORS在以下场景可以使用跨站HTTP请求:
    1,XMLHttpRequest发起的跨站HTTP请求
    2,Web字体
    3,WebGL贴图
    4,使用drawImage API在canvas上画图

    简单请求

    所谓的简单,是指:
    1,只使用 GET, HEAD 或者 POST 请求方法。如果使用 POST 向服务器端传送数据,则数据类型(Content-Type)只能是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain中的一种。
    2,不会使用自定义请求头(类似于 X-Modified 这种)。

    var invocation = new XMLHttpRequest();
    var url = 'http://bar.other/resources/public-data/';
       
    function callOtherDomain() {
      if(invocation) {    
        invocation.open('GET', url, true);
        invocation.onreadystatechange = handler;
        invocation.send(); 
      }
    }
    

    预请求

    不同于上面讨论的简单请求,“预请求”要求必须先发送一个 OPTIONS 请求给目的站点,来查明这个跨站请求对于目的站点是不是安全可接受的。这样做,是因为跨站请求可能会对目的站点的数据造成破坏。 当请求具备以下条件,就会被当成预请求处理:

    1, 请求以 GET, HEAD 或者 POST 以外的方法发起请求。或者,使用 POST,但请求数据为 application/x-www-form-urlencoded, multipart/form-data 或者 text/plain 以外的数据类型。比如说,用 POST 发送数据类型为 application/xml 或者 text/xml 的 XML 数据的请求。
    2, 使用自定义请求头(比如添加诸如 X-PINGOTHER)

    var invocation = new XMLHttpRequest();
    var url = 'http://bar.other/resources/post-here/';
    var body = '{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}Arun';
        
    function callOtherDomain(){
      if(invocation)
        {
          invocation.open('POST', url, true);
          invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
          invocation.setRequestHeader('Content-Type', 'application/xml');
          invocation.onreadystatechange = handler;
          invocation.send(body); 
        }
    
    ......
    

    服务器与浏览器之间具体的交互过程:
    使用一个 OPTIONS 发送了一个“预请求”,来探明服务器端是否接受后续真正的请求。

    OPTIONS /resources/post-here/ HTTP/1.1
    Host: bar.other
    User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en-us,en;q=0.5
    Accept-Encoding: gzip,deflate
    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
    Connection: keep-alive
    Origin: http://foo.example
    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: X-PINGOTHER
    
    
    HTTP/1.1 200 OK
    Date: Mon, 01 Dec 2008 01:15:39 GMT
    Server: Apache/2.0.61 (Unix)
    Access-Control-Allow-Origin: http://foo.example
    Access-Control-Allow-Methods: POST, GET, OPTIONS
    Access-Control-Allow-Headers: X-PINGOTHER
    Access-Control-Max-Age: 1728000
    Vary: Accept-Encoding, Origin
    Content-Encoding: gzip
    Content-Length: 0
    Keep-Alive: timeout=2, max=100
    Connection: Keep-Alive
    Content-Type: text/plain
    
    POST /resources/post-here/ HTTP/1.1
    Host: bar.other
    User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en-us,en;q=0.5
    Accept-Encoding: gzip,deflate
    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
    Connection: keep-alive
    X-PINGOTHER: pingpong
    Content-Type: text/xml; charset=UTF-8
    Referer: http://foo.example/examples/preflightInvocation.html
    Content-Length: 55
    Origin: http://foo.example
    Pragma: no-cache
    Cache-Control: no-cache
    
    Arun
    
    
    HTTP/1.1 200 OK
    Date: Mon, 01 Dec 2008 01:15:40 GMT
    Server: Apache/2.0.61 (Unix)
    Access-Control-Allow-Origin: http://foo.example
    Vary: Accept-Encoding, Origin
    Content-Encoding: gzip
    Content-Length: 235
    Keep-Alive: timeout=2, max=99
    Connection: Keep-Alive
    Content-Type: text/plain
    
    [Some GZIP'd payload]
    

    随同 OPTIONS 请求,以下两个请求头一起被发送:

    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: X-PINGOTHER
    

    请求头Access-Control-Request-Method可以提醒服务器跨站请求将使用POST方法,而请求头Access-Control-Request-Headers则告知服务器该跨站请求将携带一个自定义请求头X-PINGOTHER。这样,服务器就可以决定,在当前情况下,是否接受该跨站请求访问。

    Access-Control-Allow-Origin: http://foo.example
    Access-Control-Allow-Methods: POST, GET, OPTIONS
    Access-Control-Allow-Headers: X-PINGOTHER
    Access-Control-Max-Age: 1728000
    

    响应头Access-Control-Allow-Methods表明服务器可以接受POST, GET和 OPTIONS的请求方法。响应头Access-Control-Allow-Headers则表示服务器接受自定义请求头X-PINGOTHER。最后,响应头Access-Control-Max-Age告诉浏览器,本次“预请求”的响应结果有效时间是多久。在上面的例子里,1728000秒代表着20天内,浏览器在处理针对该服务器的跨站请求,都可以无需再发送“预请求”,只需根据本次结果进行判断处理。

    参考:HTTP访问控制(CORS)

    相关文章

      网友评论

          本文标题:HTTP访问控制(CORS)

          本文链接:https://www.haomeiwen.com/subject/pgiolttx.html