简单请求
所谓的简单,是指:
只使用 GET, HEAD 或者 POST 请求方法。
如果使用 POST 向服务器端传送数据,则数据类型(Content-Type)只能是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain中的一种。
不会使用自定义请求头(类似于 X-Modified 这种)。
类似于下面这种情况
请求头
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
可以看到响应头,服务器设置Access-Control-Allow-Origin: *,这表明服务器接受来自任何站点的跨站请求。
如果服务器端仅允许来自http://foo.example的跨站请求,它可以返回:Access-Control-Allow-Origin:http://foo.example
预请求
不同于上面讨论的简单请求,“预请求”要求必须先发送一个 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)
这种情况使用一个 OPTIONS 发送了一个“预请求”。
Firefox 3.1 根据请求参数,决定需要发送一个“预请求”,来探明服务器端是否接受后续真正的请求。
OPTIONS 是 HTTP/1.1 里的方法,用来获取更多服务器端的信息,是一个不应该对服务器数据造成影响的方法。
随同 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
附带凭证信息的请求
前面的跨域问题得到解决了,但是又发现一个问题,就是cookie无法携带问题。
原因在此:
XMLHttpRequest和访问控制功能,最有趣的特性就是,发送凭证请求(HTTP Cookies和验证信息)的功能。一般而言,对于跨站请求,浏览器是不会发送凭证信息的。但如果将XMLHttpRequest的一个特殊标志位设置为true,浏览器就将允许该请求的发送。
方法:
服务器设置
Access-Control-Allow-Credentials: true
另一方面,开发者必须在AJAX请求中打开withCredentials属性。如果是用的jq的ajax请求,就在ajax请求中加上这样的语句:
xhrFields:
{
withCredentials: true
},
crossDomain: true,
如果是XMLHTTP请求方式:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
值得注意的是:
如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。