最后,我们还要对JSONP技术再强调两点:
虽然存在一些缺陷,但JSONP的浏览器兼容性却是非常好的,可以说是一种非常小巧高效的跨域资源获取技术。
(二)官方推荐的跨域资源共享方案:CORSCORS是W3C颁布的一个浏览器技术规范,其全称为“跨域资源共享”(Cross-origin resource sharing),它的意义在于,它是由W3C官方推广的允许通过AJAX技术跨域获取资源的规范,因此相较于JSONP而言,功能更加强大,使用起来也没有了hack的味道。
关于CORS的具体细节,我建议你可以移步阮一峰的同主题博客阅读,我认为该文章已经将这个主题讲解的十分透彻了。
你当然也可以选择继续向下阅读,看看我是怎样理解CORS技术并重新梳理CORS技术相关知识的,希望也能给你带来帮助。
我们之前提到过,如果想要绕过浏览器“同源策略”,实现使用AJAX技术跨域获取资源,需要服务端和客户端的协同合作。而对于CORS标准而言,实现AJAX跨域获取资源,重点还在于服务器端返回的响应是否清楚的告知了浏览器此次跨域AJAX请求的合法性。
那么?服务器端该如何向浏览器传达这一信息呢?答案是要看AJAX请求的复杂程度,也就是说,对于简单的AJAX请求,服务器要向浏览器做出的“说明”就少,而如果是复杂的AJAX,服务器则要向浏览器多“解释”几句。
那么,如何区分AJAX请求的复杂度呢,标准在于简单的AJAX请求 只符合 下面两个条件:
而当浏览器检测到一个简单的跨域AJAX请求,浏览器会首先为我们添加一个头部信息: Origin 它的值为请求发送代码所在的源(希望你还记得,一个 源 由“ 协议 ”,“ 域名 和 端口 ”组成)。类似这样:
GET /cors HTTP/1.1 Origin: Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0 ...而当这样的一条HTTP请求发送到服务端时,服务端会检测该请求报头中的 Origin 字段的值是否在许可范围内,如果的确是服务端认可的域,那么服务端会在响应报文中添加如下字段:
CORS规范规定,客户端 XMLHttpRequest 对象的 getResponseHeader() 方法只能拿到6个基本的字段: * Cache-Control :表示响应遵循的缓存机制; * Content-Language :表示响应体的语言; * Content-Type :表示响应体的MIME类型; * Expires :表示文档的过期时间,到期不再缓存; * Last-Modified :表示文档的最后改动时间; * Pragma :用来包含特定的指令; 但是当客户端想要获取额外的响应头字段时,就需要服务端通过在该字段后定义相应的客户端可获取的响应头字段名称。
以上就是简单跨域AJAX请求,客户端与服务端的交互,在继续介绍复杂的跨域AJAX请求前,让我们先停一停,回过头来看看响应报头的 Access-Control-Allow-Origin 字段,谈一谈CORS规范中为什么默认不允许跨域AJAX请求携带Cookie,以及如果客户端需要传送Cookie时,客户端与服务端又该如何交互的问题。
首先,我们要知道,在客户端与服务端数据传输的过程中,Cookie一直是以明文的形式伴随着数据的传输,只要客户端发送了Cookie至服务端,服务端就会至少返回该段Cookie。而我们又提到过,大多数网站都使用Cookie短暂存储用户会话中的身份信息,因此将Cookie暴露在外是存在安全隐患的,CSRF攻击的目的便是获取用户的Cookie信息,因此在跨域AJAX请求中,为了减少Cookie泄露的风险,CORS规范默认禁止跨域AJAX请求携带Cookie。
那么如果客户端实在需要携带Cookie信息怎么办呢?正如上文提到过的,需要客户端与服务端一起配合,让我们看看具体细节:
开发者需要在创建XMLHttpRequest对象实例时,手动配置 withCredentials 属性,将其值设置为 true :
var xhr = new XMLHttpRequest() xhr.withCredentials = true某些浏览器会默认允许在跨域AJAX请求中发送Cookie,此时如果不想要发送Cookie,你只需要将其值设置为 false 。
对于服务端而言,除了像之前提到的要在响应报头设置 Access-Control-Allow-Credential 字段的值为 true 之外,还需要为 Access-Control-Allow-Origin 字段设置一个明确的域,不可以再使用 * 号。
相信你也能明白,这一切都是为了保护客户端与服务端Cookie的隐私和安全。
现在我们可以继续我们的主题,一起看一看如果我们的跨域AJAX请求超出了“简单”的标准,客户端与服务端又应该如何相互配合,实现跨域的资源共享。