前后端分离模大势所趋,跨域问题更是老生常谈。

《程序员应对浏览器同源策略的姿势》一文提到三种跨域请求方案,重点讲述了w3c和浏览器厂商推出的CORS规范。

同源策略  所谓同源是指域名、协议、端口相同。不同源的浏览器脚本(javascript、ActionScript、canvas)在没有明确授权的情况下,不能读写对方的资源, 这是浏览器最基本的安全规范。

CORS是w3c和浏览器厂商为解决跨域资源共享问题而推出的标准方案:

浏览机器一旦发现跨域请求,就会自动添加一些附加的头信息,有时还会多出一次附加的请求(浏览器自动完成,用户不会察觉),服务器响应特定标头Access-Control-,体现对跨源访问的授权态度。


今天我主要想要聊一聊CORS中的预检请求

当前端使用脚本请求一个跨域资源时,如果是非简单请求(下文会解释),浏览器会自动帮你先发出一个OPTIONS查询请求,称为预检(cors-preflight-request),作用是询问服务器当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段;只有得到肯定答复,浏览器才会发出正式的跨域请求。

"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

该请求header中会包含以下两个字段:

  • Access-Control-Request-Method: 该字段的值对应当前请求类型,例如 GET、POST、PUT等等。浏览器会自动处理。

  • Access-Control-Request-Headers: 该字段的值对应当前请求可能会携带的额外的自定义header字段名,多个字段用逗号分割。浏览器会自动处理,将请求中非简单的header字段全部列出来,例如标识请求流水的x-request-id,用于Auth鉴权的Authorization 字段。

对于OPTIONS请求,按照规范实现的服务端会响应一组HTTP header,但不会返回任何实体内容。如果服务端支持该跨域请求,建议返回204状态码(返回200也可以);如果不支持,建议返回403状态码(返回404或其他错误状态码也可以)。

响应的header可以包含以下字段:

  • Access-Control-Allow-Origin: 允许哪些域被允许跨域,例如 http://qq.com 或 https://qq.com,或者设置为* ,即允许所有域访问

  • Access-Control-Allow-Credentials: 是否携带票据访问(对应fetch方法中credentials),当该值为true时,Access-Control-Allow-Origin 不允许设置为*

  • Access-Control-Allow-Methods: 标识该资源支持哪些方法,例如:POST, GET, PUT, DELETE

  • Access-Control-Allow-Headers: 标识允许哪些额外的自定义 header 字段和非简单值的字段

  • Access-Control-Max-Age: 表示可以缓存Access-Control-Allow-Methods和Access-Control-Allow-Headers提供的信息多长时间,单位秒,由服务端和浏览器默认值共同决定。

  • Access-Control-Expose-Headers: 通过该字段指出哪些额外的 header 可以被支持。

由此可见,当触发预检时,一次AJAX请求会消耗掉两个TTL,严重影响性能。

那么如何节省掉OPTIONS请求来提升性能呢?从上文可以看出,有两个方案:

  1. 发出简单请求

只要同时满足以下两个条件,就属于简单请求
(1)使用下列方法之一:

  • head

  • get

  • post

(2)请求的Heder是

  • Accept

  • Accept-Language

  • Content-Language

  • Content-Type: 只限于三个值:application/x-www-form-urlencoded、multipart/form-data、text/plain

不同时满足上面的两个条件,就属于非简单请求。很明显,我们常见的Post请求且Content-Type=application/json也属于非简单请求,也会触发预检请求。

>   如果不方便改造为简单请求,只有使用方案2了。

  1. 服务器端设置Access-Control-Max-Age字段

当第一次请求该URL时会发出OPTIONS请求,浏览器会根据返回的Access-Control-Max-Age字段缓存该OPTIONS预检请求的响应结果。在缓存有效期内,该资源的请求(URL和header字段都相同的情况下)不会再触发预检。(chrome 打开控制台可以看到,当服务器响应Access-Control-Max-Age时只有第一次请求会有预检,后面不会了。注意要开启缓存,去掉disable cache勾选)

但是要注意的是,该缓存只针对这一个请求 URL 和相同的 header,无法针对整个域或者模糊匹配 URL 做缓存(当然也可以考虑封装一下,固定一个接口地址,传不同的body内容)。

以上便是对CORS OPTIONS预检请求的一些思考,希望对同学们有所帮助!

最后是Abp vNtext配置CORS的示例:

private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration)
{context.Services.AddCors(options =>{// 无阻塞跨域options.AddPolicy(DefaultCorsPolicyName, builder =>{builder.SetIsOriginAllowed(_ => true).AllowCredentials().AllowAnyHeader().WithMethods(HttpMethods.Get, HttpMethods.Post, HttpMethods.Put, HttpMethods.Delete).SetPreflightMaxAge(TimeSpan.FromHours(24));});});
}

- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age

-  程序员应对浏览器同源策略的姿势

关注并星标我们
更多干货及最佳实践分享

对CORS OPTIONS预检请求的一些思考相关推荐

  1. OPTIONS预检请求

    1.options请求是什么?什么时候浏览器会发送预检请求 options是预检请求,在真正的请求发送出去之前,浏览器都会先发送一个options请求 向服务器询问此接口是否允许我访问.浏览器在当前真 ...

  2. 从前后端的角度分析options预检请求——打破前后端联调的理解障碍

    文章目录 1.从前端的角度看options--post请求之前一定会有options请求?信口雌黄! 2.从后端的角度看options--post请求之前一定会有options请求?胡说八道! 1.从 ...

  3. CORS - 引入预检请求的动机是什么?

    本文翻译自:CORS - What is the motivation behind introducing preflight requests? Cross-origin resource sha ...

  4. CORS预检请求详谈

    引言 最近在项目中因前后端部署不同地方,前端在请求后端api时发生了跨域请求,我们采用CORS(跨域资源共享)来解决跨域请求,这需要前后端的配合来完成.在这一过程中,后端支持了CORS跨域请求后,前端 ...

  5. 什么时候会发送options请求(预检请求)

    OPTIONS请求即预检请求,可用于检测服务器允许的http方法.当发起跨域请求时,由于安全原因,触发一定条件时浏览器会在正式请求之前自动先发起OPTIONS请求,即CORS预检请求,服务器若接受该跨 ...

  6. 跨域请求避免OPTIONS请求(预检请求)

    有时候前后端分离域名不一致,会造成跨域请求 而跨域请求有时候会自动发起两次请求,第一次为预检请求,即OPTIONS请求 一般来说使用 application/json 的 post 请求是必然会带入O ...

  7. 浏览器预检请求返回400 has been blocked by CORS policy: Response to preflight request doesn’t pass access cont

    这个问题也是很过分头一次遇到,原因是谷歌浏览器在有跨域(CORS)请求时,会先发送一个preflight(预检)请求,之后才会发送fetch请求. CORS:跨源资源共享 (CORS)(或通俗地译为跨 ...

  8. 对预检请求的响应未通过访问控制检查

    本文翻译自:Response to preflight request doesn't pass access control check I'm getting this error using n ...

  9. vue跨域拦截浏览器options预检

    当你跨域访问接口的时候,会发现你的接口请求了两次,然后仔细对比一下会发现请求类型并不一致,一个是OPTIONS,另一个是你的POST请求.事情是这样发生的,当浏览器发现你准备跨域进行非简单请求的时候( ...

最新文章

  1. PgSQL · 特性分析 · full page write 机制
  2. Windows上安装Nacos
  3. Unity Note 1
  4. 提升工作沟通,你需要明白这些内容
  5. 通过nginx配置文件抵御攻击,防御CC攻击的经典思路!
  6. P3564 [POI2014]BAR-Salad Bar(ST表 + 二分)
  7. java jwt 验证_教程:用Java创建和验证JWT
  8. 【C++】VS2010将写好的程序打包成安装文件发布
  9. JQuery根据关键字检索html元素并筛选显示
  10. Docker学习总结(40)——Docker常见应用场景再总结
  11. AIR访问操作系统剪贴板粘贴操作延迟呈现解决办法
  12. Github 开源趋势榜 TOP 1:英伟达升级发布二代 StyleGAN!
  13. [转]STL(容器)与DEBUGNEW运算符冲突的解决
  14. Oracle字符集及其查看和修改
  15. java里如何表示黑桃方片_扑克牌中(黑桃,方片,红心,梅花)各代表什么意思?据我所知红心是代表爱。...
  16. UG NX 10 草图之草图基准设置
  17. 简单的文本编辑器C语言实现
  18. android协议分析,对一个apk的协议分析
  19. 利用QQ文件中转站给多个好友或群友传送文件
  20. android 11.0 12.0自定义开机向导app

热门文章

  1. 使用RestTemplate时报错java.lang.IllegalStateException: No instances available for 127.0.0.1
  2. 智能停车O2O 独角兽初现:“ETCP停车”获5000万美金A轮融资
  3. 单一职责原则--设计模式系列
  4. Cnblogs自定义皮肤css样式-星空观测者
  5. SRM 588 D2 L2:GUMIAndSongsDiv2,冷静思考,好的算法简洁明了
  6. Dave Python 练习三 -- 对象
  7. powerpoint转换器_如何将PowerPoint演示文稿转换为主题演讲
  8. apt-get更新软件包_如何使用Apt-fast加速软件包下载和更新
  9. 使用T-SQL找出执行时间过长的作业
  10. #celery#周期性任务