最近写的项目,应用里全部的ajax请求都发送了2遍。因为新项目,基础模块是新搭的,因此出现一些奇葩问题也是意料之中,啊终于第一次在chrome的devTools碰见了活的options请求。 ios
这里首先发送了一次额外的options请求,在浏览器里看到请求request header 和 response header的信息以下:ajax
Request Header | 做用 |
---|---|
Access-Control-Request-Method | 告诉服务器实际请求所使用的 HTTP 方法 |
Access-Control-Request-Headers | 告诉服务器实际请求所携带的自定义首部字段,本次实际请求首部字段中content-type为自定义 |
服务器基于从预检请求头部得到的信息来判断,是否接受接下来的实际请求。 chrome
response header | 做用 |
---|---|
Access-Control-Allow-Methods | 返回了服务端容许的请求,包含GET/HEAD/PUT/PATCH/POST/DELETE |
Access-Control-Allow-Credentials | 容许跨域携带cookie(跨域请求要携带cookie必须设置为true) |
Access-Control-Allow-Origin | 容许跨域请求的域名,这个能够在服务端配置一些信任的域名白名单 |
Access-Control-Request-Headers | 客户端请求所携带的自定义首部字段content-type |
这次OPTIONS请求返回了响应头的内容,但没有返回响应实体response body内容。 json
这是原本要发送的请求,如图所示是普通的post请求。其中Content-Type的application/json是这次和后端约定的请求内容格式,这个也是后面讲到为何会发送options请求的缘由之一。 axios
从不少资料咱们能够了解到使用OPTIONS方法对服务器发起请求,能够检测服务器支持哪些 HTTP 方法。可是此次咱们并无主动去发起OPTIONS请求,那OPTIONS请求为什么会自动发起?后端
MDN的CORS一文中提到:跨域
规范要求,对那些可能对服务器数据产生反作用的 HTTP 请求方法(特别是 GET 之外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否容许该跨域请求。浏览器
因此这个跨域请求触发了浏览器自动发起OPTIONS请求,看看这次跨域请求具体触发了哪些条件。缓存
CORS预检请求触发条件 | 本次请求是否触发该条件 |
---|---|
1. 使用了下面任一HTTP 方法: | |
PUT/DELETE/CONNECT/OPTIONS/TRACE/PATCH | 否,本次为post请求 |
2. 人为设置了如下集合以外首部字段: | |
Accept/Accept-Language/Content-Language/Content-Type/DPR/Downlink/Save-Data/Viewport-Width/Width | 否,未设置其余头部字段 |
3. Content-Type 的值不属于下列之一: | |
application/x-www-form-urlencoded、multipart/form-data、text/plain | 是,为application/json |
因为修改了Content-Type为application/json,触发了CORS预检请求。安全
可见一旦达到触发条件,跨域请求便会一直发送2次请求,这样增长的请求数是否可优化呢?答案是能够,OPTIONS预检请求的结果能够被缓存。
Access-Control-Max-Age这个响应首部表示 preflight request (预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 能够被缓存的最长时间,单位是秒。(MDN)
若是值为 -1,则表示禁用缓存,每一次请求都须要提供预检请求,即用OPTIONS请求进行检测。
评论区的朋友提醒了,尽可能避免不要触发OPTIONS请求,上面例子中把content-type改掉是能够的。在其余场景,好比跨域而且业务有自定义请求头的话就很难避免了。如今使用的axios或者superagent等第三方ajax插件,若是出现CORS预检请求,能够看看默认配置或者二次封装是否规范。
OPTIONS请求即预检请求,可用于检测服务器容许的http方法。当发起跨域请求时,因为安全缘由,触发必定条件时浏览器会在正式请求以前自动先发起OPTIONS请求,即CORS预检请求,服务器若接受该跨域请求,浏览器才继续发起正式请求。