对CROS OPTIONS预检请求的一些思考
前后端分离模大势所趋,跨域问题更是老生常谈。
问题背景:
浏览器最基本的安全规范-同源策略。所谓同源是指域名、协议、端口相同。不同源的浏览器脚本(javascript、ActionScript、canvas)在没有明确授权的情况下,不能读写对方的资源。
CORS就是w3c和浏览器厂商为解决跨域资源共享问题而推出的标准方案:它允许浏览器向跨源服务器发出脚本请求,CORS需要浏览器和服务器同时支持,它的通信过程都是浏览器自动完成的,不需要用户参与。
浏览机器一旦发现跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会察觉,服务器响应特定标头Access-Control-,体现跨源访问的授权。
今天我主要想要聊一聊CORS中的预检请求
当前端使用脚本请求一个跨域资源时,如果是非简单请求(下文会解释),浏览器会自动帮你先发出一个OPTIONS查询请求,称为预检(cors-preflight-request),作用是询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用那些HTTP动词和头信息字段。 只有得到肯定答复,浏览器才会发生正式的XHR请求。

该请求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)使用下列方法之一:
- 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了。
- 服务器端设置
Access-Control-Max-Age字段
当第一次请求该URL时会发出OPTIONS请求,浏览器会根据返回的Access-Control-Max-Age字段缓存该请求的OPTIONS预检请求的响应结果。在缓存有效期内,该资源的请求(URL和header字段都相同的情况下)不会再触发预检。(chrome 打开控制台可以看到,当服务器响应Access-Control-Max-Age 时只有第一次请求会有预检,后面不会了。注意要开启缓存,去掉disable cache勾选)
但是要注意的是,该缓存只针对这一个请求 URL 和相同的 header,无法针对整个域或者模糊匹配URL做缓存。(当然也可以考虑封装一下,固定一个接口地址,传不同的body内容)。
下面是Abp vNext配置CROS的示例:
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));
});
});
}
对CROS OPTIONS预检请求的一些思考的更多相关文章
- OPTIONS预检请求
OPTIONS预检请求 背景:像后台发送一个post请求,出错,错误代码403(权限验证未通过),查看请求方法变成OPTIONS.检查请求头得知,当前请求token未带上,问题,为什么post请求变成 ...
- 跨域请求中预检请求options之坑
一.前言 因为跨域请求,浏览器可能(后面讲)会发送一次options请求,如果处理不好,跨域还是会gg的. 之前很少涉及跨域,涉及也是简单请求(下面阮老师文章中区别热简单请求和复杂请求),所以基本不会 ...
- CORS预检请求详谈
引言 最近在项目中因前后端部署不同地方,前端在请求后端api时发生了跨域请求,我们采用CORS(跨域资源共享)来解决跨域请求,这需要前后端的配合来完成.在这一过程中,后端支持了CORS跨域请求后,前端 ...
- Cross-origin resource sharing JSON with Padding 同源策略 JSONP 为什么form表单提交没有跨域问题,但ajax提交有跨域问题? XMLHttpRequest and the Fetch API follow the same-origin policy 预检请求(preflight request)
https://zh.wikipedia.org/wiki/跨来源资源共享 跨来源资源共享(CORS)是一份浏览器技术的规范,提供了 Web 服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略[1 ...
- preflight request预检请求
preflight request预检请求,负责检查是否允许跨域请求,但是注意并不是所有的跨域请求都会发送preflight请求.对与那些幂等的请求,如GET请求,就不会发送preflight请求.只 ...
- ASP Net Core – CORS 预检请求
CORS(跨源资源共享)是一种机制,它允许同一个来源运行的Web应用程序从在另一个来源运行的服务器访问资源.同源策略是一种非常严格的措施,因为它只允许与服务器起源于同一源的应用程序访问其资源.很多时候 ...
- 跨域时发送预检请求,tp5的restful无options方法的解决方案
解决 跨域问题解决 问题:使用vue-resource发送delete请求时报options请求404 思考:明明发送的是delete请求,为何变成了options请求? 答:跨域情况下,PUT,DE ...
- 在fetch方法中添加header后遇到的预检请求问题
今天在使用fetch方法 fetch('xxx.com',{header:{bbbbbbb:111}}) 浏览器返回的请求信息中,header变成了 :authority:koss.nocorp.me ...
- web api 设置允许跨域,并设置预检请求时间
<httpProtocol> <customHeaders> <!--响应类型 (值为逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法)--> <ad ...
随机推荐
- 第15.37节 PyQt(Python+Qt)入门学习:containers容器类部件QMdiArea多文档界面部件详解及编程开发案例
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.引言 老猿在前期学习PyQt相关知识时,对每个组件的属性及方法都研 ...
- PyQt(Python+Qt)学习随笔:QTabWidget选项卡部件的tabBar、count、indexOf方法
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QTabWidget的每个选项卡都有一个对应的页面部件对象,可用通过count方法获取选项卡个数,可 ...
- PyQt(Python+Qt)学习随笔:formLayout的layoutLabelAlignment 属性
一.引言 Qt Designer的表单布局(formLayout)中,layoutLabelAlignment 用于控制表单布局中标签的水平对齐方式(包括垂直和水平方向两个方向).如图: 此属性实际对 ...
- CNVD漏洞证书(1)
之前申请了CNVD原创漏洞,踩了坑,记录一下 有很多师傅写过相关的文章: https://blog.csdn.net/qq1124794084/article/details/82657840 htt ...
- 如何在苹果电脑上创建一个html格式文件,并在浏览器正确打开
之前一直使用windows系统的电脑,创建文件很简单,改格式也非常的简单.但换了苹果电脑,如何创建一个HTML文件?却把我给整蒙了. 首先,为什么mac上不能直接新建文本文件? 因为mac一都是以应用 ...
- react路由初探(1)
import React from 'react'; import logo from './logo.svg'; import './App.css'; class About extends Re ...
- 记一次storm提交任务遇到的坑
摘要:主要是自己没有真正理解storm jar命令参数的意义. 情景复现: 在storm集群中使用命令提交后,在UI界面中,一直看不见任务提交上来的任务,但是在集群提交的shell界面中,是可以看到相 ...
- Python中open函数怎么操作文件
在 Python 中,如果想要操作文件,首先需要创建或者打开指定的文件,并创建一个文件对象,而这些工作可以通过内置的 open() 函数实现. open() 函数用于创建或打开指定文件,该函数的常用语 ...
- C#数据结构-线索化二叉树
为什么线索化二叉树? 对于二叉树的遍历,我们知道每个节点的前驱与后继,但是这是建立在遍历的基础上,否则我们只知道后续的左右子树.现在我们充分利用二叉树左右子树的空节点,分别指向当前节点的前驱.后继,便 ...
- 2020-2021-1 20209307《Linux内核原理与分析》第五周作业
一.理论知识 系统调用:操作系统为用户态进程与硬件设备进行交互提供的一组接口. 系统调用的三层皮:API(应用程序接口),中断向量system_call,中断服务程序sys_xyz 宏观上Linux操 ...