跨域问题和CORS
什么是CORS
所谓跨域,通俗来说就是该网站访问了其他origin(源,由域、协议和端口组成)的资源。
浏览器发出的 XMLHttpRequest
请求有同源使用限制,默认情况下跨域请求是不被允许的。但是,每个源可以设置哪些其他源可以访问自己的资源,如果一个请求源A在源B的允许请求范围内,那么浏览器就允许请求源A对源B的跨域请求。这种检查机制就是跨源资源共享 (CORS),是一种基于 HTTP 头的机制。
简单请求和非简单请求
在介绍CORS之前,首先要明确两种不同类型的请求,简单请求
和 非简单请求
。
若请求 满足所有下述条件,则该请求可视为简单请求
:
使用下列方法之一:
- GET
- HEAD
- POST
请求的Headers只包含以下字段:
- Accept
- Accept-Language
- Content-Language
- Content-Type(需要注意额外的限制)
- 请求中的任意 XMLHttpRequest 对象均没有注册任何事件监听器;XMLHttpRequest 对象可以使用 XMLHttpRequest.upload 属性访问。
- 请求中没有使用 ReadableStream 对象。
Content-Type 的值仅限于下列三者之一:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
而不符合上述条件的则为 非简单请求
。
CORS预检请求(Preflight request)
浏览器会在必要的时候向服务器发送一个 OPTIONS
请求,用来检查服务器是否支持跨域资源共享即CORS。这个请求就叫预检请求(Preflight request)。
请求通常携带 Access-Control-Request-Method
和 Access-Control-Request-Headers
,以及一个 Origin
的首部信息。
举一个例子,在实际发送 DELETE
请求之前,会先向服务器发起一个预检 OPTIONS
请求:
1 |
|
如果服务器允许,就会相应这个请求,并在response header里面返回允许的请求源和方法:
1 |
|
这和开头的两种请求类型有什么关系呢?
简单来说,简单请求
不会触发预检请求,而 非简单请求
则会触发。这么做的原因也很简单,是否允许CORS是在响应的Header里返回的,而非简单请求
都是可能会对服务器数据产生未预期影响的操作,比如删除,修改或者是带有其他Header信息,所以要通过 OPTIONS
预检请求来验证请求是否符合CORS规则,同时又不影响服务端数据。
需要注意的是,Response Header里的 Access-Control-Max-Age
信息表示在86400秒,也就是24小时内,无需为统一请求再次发起预检请求。当然浏览器也会维护一个最大有效时间,如果Header中的最大有效时间超过了浏览器设置,则不会生效。
Response Header
跟CORS相关的Response Header,日常工作中注意在服务端,反向代理或者CDN等设置中根据实际情况进行相应设置。
1 |
|