利用CORS实现跨域请求
跨域请求一直是网页编程中的一个难题,在过去,绝大多数人都倾向于使用JSONP
来解决这一问题。不过现在,我们可以考虑一下W3C中一项新的特性——CORS(Cross-Origin Resource Sharing)了。
?
本文的所有代码均来自http://www.html5rocks.com/en/tutorials/cors/,如果您对其中的任何技术细节存在疑问,请以原文为准。
XmlHttpRequest
对象对于CORS,Chrome、FireFox以及Safari,需要使用XmlHttpRequest2
对象;而对于IE,则需要使用XDomainRequest
;Opera目前还不支持这一特性,但很快就会支持。
因此,在对象的创建上,我们不得不首先针对不同的浏览器而进行一下预处理:
?事件处理
原先的
事件说明onloadstart*当请求发生时触发onprogress读取及发送数据时触发onabort*当请求被中止时触发,如使用abort()方法onerror当请求失败时触发onload当请求成功时触发ontimeout当调用者设定的超时时间已过而仍未成功时触发onloadend*请求结束时触发(无论成功与否)XmlHttpRequest
对象仅仅只有一个事件——onreadystatechange
,用以通知所有的事件,而现在,我们除了这个事件之外又多了很多新的。注:带星号的表示IE的
XDomainRequest
仍不支持。
数据来自http://www.w3.org/TR/XMLHttpRequest2/#events。绝大多数情况下,我们只需要和
onload
及onerror
打交道,就像下面这样:?服务端
一个CORS请求可能包含多个HTTP头,甚至有多个请求实际发送,这对于客户端的开发者来说通常是透明的。因为浏览器已经负责实现了CORS最关键的部分;但是服务端的后台脚本则需要我们自己进行处理,因此我们还需要了解到服务端到底从浏览器那里收到了怎样的内容。
先来看看流程图吧。
CORS分类
CORS可以分成两种:
一个简单的请求大致如下:
HEAD
GET
POST
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type
,但仅能是下列之一application/x-www-form-urlencoded
multipart/form-data
text/plain
任何一个不满足上述要求的请求,即被认为是复杂请求。一个复杂请求不仅有包含通信内容的请求,同时也包含预请求(preflight request)。
为了搞清楚复杂请求与简单请求有何区别,我们首先来看看简单请求是怎样处理的。
JavaScript:
XMLHttpRequest cannot load http://api.alice.com. Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.?不过很可惜,浏览器并不会给出详细的错误情况,仅仅是告知我们出错而已。
跨域请求始终是网页安全中一个比较头疼的问题,CORS提供了一种跨域请求方案,但没有为安全访问提供足够的保障机制,如果你需要信息的绝对安全,不要依赖CORS当中的权限制度,应当使用更多其它的措施来保障,比如OAuth2。
CORS是W3C中一项较“新”的方案,以至于各大网页解析引擎还没有对其进行完美的实现。下面是截至2011年11月13日时的已知问题:
getAllResponseHeaders()
方法无法获取Access-Control-Expose-Headers
当中要求的信息。在Chrome/Safari当中,仅仅只有简单的头部能够读取,其他无法获取;在FireFox当中,无法获得任何信息。(FireFox Bugzilla/Webkit Bugzilla)GET
、POST
方法的复杂请求发送时没有发送预请求的环节。onerror
触发时statusText
获取不到任何内容。[转自:http://newhtml.net/using-cors/]