代码改变世界

JavaScript跨域(3):HTTP access control (CORS)跨域

2013-04-09 11:08  Barret李靖  阅读(1244)  评论(1编辑  收藏

  网上看了很多博客和文档,感觉还是Mozilla大大写的最简单、最好懂,不过文字很长。。

  原文链接:https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS

  要整篇翻译,我肯定吃不消,当然也没这个必要,下面就提要说一点吧,这个方法还存在兼容性问题,尽管有相应的解决手段,但是觉得用起来不是特别爽。

Cross-site HTTP requests are HTTP requests for resources from a different domain than the domain of the resource making the request.  For instance, a resource loaded from Domain A (http://domaina.example) such as an HTML web page, makes a request for a resource on Domain B (http://domainb.foo), such as an image, using the img element (http://domainb.foo/image.jpg).  This occurs very commonly on the web today — pages load a number of resources in a cross-site manner, including CSS stylesheets, images and scripts, and other resources.

  跨站点的HTTP请求也就是从一个域名向另一个域名发送请求(POST,GET等),比如,从http://a.com向http://b.com请求一张图片(http://b.com/images.jpg),这种请求或者说这种现象是时有发生的,所以找到一个好方法来处理这类问题也是十分有必要的。

 

Mozilla大大说

  如下,我们在http://foo.example向页面http://bar.example发送请求:

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();  
  } 
}

  可以看看服务器对浏览器的响应

GET /resources/public-data/ 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 
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html 
Origin: http://foo.example 
  
  
HTTP/1.1 200 OK 
Date: Mon, 01 Dec 2008 00:23:53 GMT 
Server: Apache/2.0.61  
Access-Control-Allow-Origin: * 
Keep-Alive: timeout=2, max=100 
Connection: Keep-Alive 
Transfer-Encoding: chunked 
Content-Type: application/xml
  
[XML Data]

  这些都是关于HTTP的一些数据和参数,如果不太明白的话,可以看看这本书《HTTP权威指南》

  前半截是FF3.5发送的文件头请求,后半截是服务器的响应。你应该注意到了我标红的那些字,这个就是本文要讲述的重点。

  在请求之前,我们也可以自己设定一些服务器要响应的内容

var invocation = new XMLHttpRequest(); 
var url = 'http://bar.other/resources/post-here/'; 
var body = '<?xml version="1.0"?><person><name>Arun</name></person>'; 
      
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);  
    } 
  
......

  setRequestHeader顾名思义就是设置请求头的一些参数。

  上面说了半天也就是告诉大家一些服务器和客户端相关参数设置和解释,还没太涉及到跨域的东西。

 

Cross Domain [跨域]

  这是我放到SAE上的一段代码(http://1.qianduannotes.sinaapp.com/test/ACAO.php

<?php
    header("Access-Control-Allow-Origin: *");
    //header("Access-Control-Allow-Origin: http://yourURL.com");
    echo "hello world";
?>

  如果我没加header("Access-Control-Allow-Origin: *")这句话,你通过ajax或者其他方式来请求这个数据是会报错的,不信就可以试试这个链接http://1.qianduannotes.sinaapp.com/test/ACAO_none.php

  其中的“*”表示所有域都可以访问,如果将Access-Control-Allow-Origin设置为一个特定的URL,那这个文件就只能被特定URL以及他的子域(http://yoururl.com/sub/)访问。

 

Compatibility [兼容性]

Show all versionsIEFirefoxChromeSafariOperaiOS SafariOpera MiniAndroid BrowserBlackberry Browser
                2.1  
                2.2  
            3.2   2.3  
            4.0-4.1   3.0  
  8.0   24.0     4.2-4.3   4.0  
  9.0 19.0 25.0 5.1   5.0-5.1   4.1  
Current 10.0 20.0 26.0 6.0 12.1 6.0 5.0-7.0 4.2 7.0
Near future   21.0 27.0           10.0
Farther future   22.0 28.0            

  最明显的就是IE(8、9)的bug,可以通过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();     

  下面附上一个MSDN上的DEMO

XDomainRequest From MSDN
<html>
<script type="text/javascript">
    var xdr;
    function readdata()
    {
        var dRes = document.getElementById('dResponse');
        dRes.innerText = xdr.responseText;
        alert("Content-type: " + xdr.contentType);
        alert("Length: " + xdr.responseText.length);
    }
    
    function err()
    {
        alert("XDR onerror");
    }
    function timeo()
    {
        alert("XDR ontimeout");
    }
    function loadd()
    {
        alert("XDR onload");
        alert("Got: " + xdr.responseText);
    }
    function progres()
    {
        alert("XDR onprogress");
        alert("Got: " + xdr.responseText);
    }
    function stopdata()
    {
        xdr.abort();
    }
    function mytest()
    {
        var url = document.getElementById('tbURL');
        var timeout = document.getElementById('tbTO');
        if (window.XDomainRequest)
        {
            xdr = new XDomainRequest();
            if (xdr)
            {
                xdr.onerror = err;
                xdr.ontimeout = timeo;
                xdr.onprogress = progres;
                xdr.onload = loadd;
                xdr.timeout = tbTO.value;
                xdr.open("get", tbURL.value);
                xdr.send();
            }
            else
            {
                alert('Failed to create');
            }
        }
        else
        {
            alert('XDR doesn't exist');
        }
    }
</script>
<body>
    <h2>XDomainRequest</h2>
    <input type="text" id="tbURL" value="http://www.contoso.com/xdr.txt" style="width:300px"><br>
    <input type="text" id="tbTO" value="10000"><br>
    <input type="button" onclick="mytest()" value="Get">&nbsp;&nbsp;&nbsp;
    <input type="button" onclick="stopdata()" value="Stop">&nbsp;&nbsp;&nbsp;
    <input type="button" onclick="readdata()" value="Read">
    <br>
    <div id="dResponse"></div>
</body>
</html>

 

Reference [参考资料]

  1.Mozilla

  2.MSDN

  3.http://caniuse.com/

  4.屈屈(关闭了页面,链接给忘了,^_^)