HTTP 跨域时的 options 请求[转]

一、简介

出于安全考虑,并不是所有域名访问后端服务都可以。其实在正式跨域之前,浏览器会根据需要发起一次预检(也就是 options 请求),用来让服务端返回允许的方法(如 GET、POST),被跨域访问的 Origin(来源或者域),还有是否需要 Credentials(认证信息)等。那么浏览器在什么情况下能预检呢?

二、两种请求方式

浏览器将 CORS 请求分为两类:简单请求(simple request)和非简单请求(not-simple-request),简单请求浏览器不会预检,而非简单请求会预检。这两种方式怎么区分?

同时满足下列三大条件,就属于简单请求,否则属于非简单请求。

  1. 请求方式只能是:GET、POST、HEAD。
  2. HTTP 请求头限制这几种字段:Accept、Accept-Language、Content-Language、Content-Type、Last-Event-ID。
  3. Content-type 只能取:application/x-www-form-urlencoded、multipart/form-data、text/plain。

对于简单请求,浏览器直接请求,会在请求头信息中,增加一个 origin 字段,来说明本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,来决定是否同意该请求,服务器返回的响应会多几个头信息字段,如图所示:上面的头信息中,三个与 CORS 请求相关,都是以 Access-Control- 开头。

  1. Access-Control-Allow-Origin:该字段是必须的,* 表示接受任意域名的请求,还可以指定域名。
  2. Access-Control-Allow-Credentials:该字段可选,是个布尔值,表示是否可以携带 cookie(注意:如果 Access-Control-Allow-Origin 字段设置 *,此字段设为 true 无效)。
  3. Access-Control-Allow-Headers:该字段可选,里面可以获取 Cache-Control、Content-Type、Expires 等,如果想要拿到其他字段,就可以在这个字段中指定。比如图中指定的 GUAZISSO。

非简单请求是对那种对服务器有特殊要求的请求,比如请求方式是 PUT 或者 DELETE,或者 Content-Type 字段类型是 application/json。都会在正式通信之前,增加一次 HTTP 请求,称之为预检。浏览器会先询问服务器,当前网页所在域名是否在服务器的许可名单之中,服务器允许之后,浏览器会发出正式的 XMLHttpRequest 请求,否则会报错。(备注:之前碰到预检请求后端没有通过,就不会发正式请求,然后找了好久原因,原来后端给忘了设置...)Java 后端实现拦截器,排除 Options。

JAVA 代码片段

就 Content-Type 为 application/json 为例:对比两张图片,一次预检请求,一 次正式请求。

预检请求

正式请求

很明显,请求头中预检请求不会携带 cookie,正式请求会携带 cookie 和参数。跟普通请求一样,响应头也会增加同样字段。

一旦服务器通过了“预检”请求,以后每次浏览器正常的 CORS 请求,就都跟简单请求一样。

版权声明

本博客所有的转载文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Alvin_9d9c和本文原始地址:https://www.jianshu.com/p/5cf82f092201

发表评论

电子邮件地址不会被公开。 必填项已用*标注