options 请求引起的请求失败问题
问题描述:
fetch 请求跨域失败,浏览器提示报错信息:TypeError: Failed to fetch
Server 请求头配置为:
Access-Control-Allow-Origin: ‘xx 地址’
Access-Control-Allow-Headers: ‘Content-Type, origin, Accept, X-Requested-With’
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST
Access-Control-Max-Age: ‘2592000’
请求示例:
fetch('xxx', {
headers: {'Content-type': 'application/json'},
method: "GET",
mode: "cors"
}).then(res => res.json())
问题分析: 咋一看其实配置的请求头没什么问题,但为什么请求会失败呢。当尝试去掉 fetch 中的 headers 后发现就不报错了,这是为什么呢?
查阅资料发现,原来是因为 options 请求导致的,配置中的 Access-Control-Allow-Methods 并没有加 OPTIONS 所以请求失败了。
但为什么 Content-type 会发起 OPTIONS 请求呢?下面我们深入了解下 OPTIONS 请求
OPTIONS 请求
除了主动发起 OPTIONS 时,什么时候会自动发起 OPTIONS 请求呢?
在 (MDN CORS)[https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS] 中可以看到:
对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。
所以跨域请求触发了浏览器自动发起 OPTIONS 请求。我们再来看下具体触发的条件有哪些: CORS 预检请求触发条件
- 使用了下面任一 HTTP 方法: PUT/DELETE/CONNECT/OPTIONS/TRACE/PATCH
- 人为设置了以下集合之外首部字段: Accept/Accept-Language/Content-Language/Content-Type/DPR/Downlink/Save-Data/Viewport-Width/Width
- Content-Type 的值不属于下列之一: application/x-www-form-urlencoded、multipart/form-data、text/plain
所以之所以会导致上述提到的问题,其实就是满足了第三个条件。