浏览器一般使用 CORS(跨域资源共享)来处理跨域问题。同源导致了不同源数据不能互相访问,而在开发中我们很多时候需要用第一个页面的脚本访问第二个页面里的数据,所以制定了一些允许跨域的策略
跨域
CORS(Cross-origin resource sharing,跨域资源共享)是一个 W3C 标准,定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通。其核心思想是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,来决定请求或响应是应该成功,还是失败。决定请求成功或者失败是由服务器来判断的
整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉
CORS 请求
对于非简单请求与简单请求,CORS 的处理方式是不一样的。只要请求方法是 get、head、post 这三种方法之一,并且 HTTP 的头信息不超出规定的几种字段:
Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type 就可以认为是简单请求
简单请求
对于简单请求的处理,在请求头中需要附加一个额外的 Origin 字段,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头部信息来决定是否给予响应。例如:Origin: http://www.laixiangran.cn
如果服务器认为这个请求可以接受,就在 Access-Control-Allow-Origin (这个字段是必须的) 字段中回发相同的源信息,例如:Access-Control-Allow-Origin:http://www.laixiangran.cn
复杂请求
对于复杂请求,浏览器在发送真正的请求之前,会先发送一个预检请求给服务器,该请求的大致作用是用于请求服务器对于某些接口等资源的支持情况的,包括各种请求方法、头部的支持情况,仅作查询使用。这种请求使用 OPTIONS 方法,当 OPTIONS 请求成功返回后,真正的 AJAX 请求才会再次发起
该请求的请求头部包含下列内容:
- Origin:与简单的请求相同
- Access-Control-Request-Method: 请求自身使用的方法
- Access-Control-Request-Headers: (可选)自定义的头部信息,多个头部以逗号分隔
发送这个请求后,服务器可以决定是否允许这种类型的请求。服务器通过在响应头添加如下信息与浏览器进行沟通:
- Access-Control-Allow-Origin:与简单的请求相同
- Access-Control-Allow-Methods: 允许的方法,多个方法以逗号分隔
- Access-Control-Allow-Headers: 允许的头部,多个方法以逗号分隔
- Access-Control-Max-Age: 应该将这个 Preflight 请求缓存多长时间(以秒表示)
除了以上的标签,返回的其他标签也可以作为判断信息来使用,以下是一个例子:
->>> curl -X OPTIONS https://xxxx.com/micro/share/getShareRecord -i
HTTP/1.1 200 OK
Server: nginx/1.13.3
Date: Mon, 30 Jul 2018 12:50:08 GMT
Content-Length: 0
Connection: keep-alive
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
X-Frame-Options: SAMEORIGIN
Access-Control-Allow-Origin: 0
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: X-Requested-With
OPTIONS 请求的发送时浏览器行为,由浏览器自主发起。除了 CORS 之外还有其他的跨域解决方式