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

问题背景:

浏览器最基本的安全规范-同源策略。所谓同源是指域名、协议、端口相同。不同源的浏览器脚本(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.comhttps://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内容)。

下面是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预检请求的一些思考的更多相关文章

  1. OPTIONS预检请求

    OPTIONS预检请求 背景:像后台发送一个post请求,出错,错误代码403(权限验证未通过),查看请求方法变成OPTIONS.检查请求头得知,当前请求token未带上,问题,为什么post请求变成 ...

  2. 跨域请求中预检请求options之坑

    一.前言 因为跨域请求,浏览器可能(后面讲)会发送一次options请求,如果处理不好,跨域还是会gg的. 之前很少涉及跨域,涉及也是简单请求(下面阮老师文章中区别热简单请求和复杂请求),所以基本不会 ...

  3. CORS预检请求详谈

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

  4. 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 ...

  5. preflight request预检请求

    preflight request预检请求,负责检查是否允许跨域请求,但是注意并不是所有的跨域请求都会发送preflight请求.对与那些幂等的请求,如GET请求,就不会发送preflight请求.只 ...

  6. ASP Net Core – CORS 预检请求

    CORS(跨源资源共享)是一种机制,它允许同一个来源运行的Web应用程序从在另一个来源运行的服务器访问资源.同源策略是一种非常严格的措施,因为它只允许与服务器起源于同一源的应用程序访问其资源.很多时候 ...

  7. 跨域时发送预检请求,tp5的restful无options方法的解决方案

    解决 跨域问题解决 问题:使用vue-resource发送delete请求时报options请求404 思考:明明发送的是delete请求,为何变成了options请求? 答:跨域情况下,PUT,DE ...

  8. 在fetch方法中添加header后遇到的预检请求问题

    今天在使用fetch方法 fetch('xxx.com',{header:{bbbbbbb:111}}) 浏览器返回的请求信息中,header变成了 :authority:koss.nocorp.me ...

  9. web api 设置允许跨域,并设置预检请求时间

    <httpProtocol> <customHeaders> <!--响应类型 (值为逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法)--> <ad ...

随机推荐

  1. Sql注入--数字型手工测试

    Sql注入--数字型手工测试 漏洞原因:是在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的"数据"拼接到SQL语句中后,被当作SQL语句的一部分执行. 从而 ...

  2. RSA简单实践

    RSA公钥文件解密密文的原理分析 前言 最近在学习 RSA 加解密过程中遇到一个这样的难题:假设已知 publickey 公钥文件和加密后的密文 flag ,如何对其密文进行解密,转换成明文~~ 分析 ...

  3. GBK宽字节注入SQL

    SQL注入:宽字节注入(GBK双字节绕过) 2015-06-09lyiang 宽字节注入的作用是非常大的,实际上在代码层的防御一般不外乎两种,一是反斜杠转义,而就是replace替换成空字节,之前的替 ...

  4. C#获取引用组件的版本信息

    /// <summary>        /// 当前目录下文件版本        /// </summary>        public void FilesVersion ...

  5. APIO2012 苦无 Kunai

    这题网上貌似还没有完整的题解呢,我来口胡一下~ Description \(W \times H\) 的二维坐标系,\(W, H \le 10^9\) 给 \(n (n \le 10^5)\) 个点 ...

  6. 题解-CF617E XOR and Favorite Number

    题面 CF617E XOR and Favorite Number 给定 \(n,m,k\) 和 \(n\) 个数的序列 \(a_i\),\(m\) 次求区间 \([l,r]\) 中异或值为 \(k\ ...

  7. 【Jmeter 压测MySql连接问题】

    JDBC Request :Cannot load JDBC driver class 'com.mysql.jdbc.Driver'解决办法   在Jmeter中run JDBC Request时, ...

  8. 编译opencv4.5.0

    1. 环境vs2017或其它版本cmake-3.18设置环境变量OPENCV_TEST_DATA_PATH 值设置为 D:\sdk\vs2017\opencv-4.5.0\opencv_extra-4 ...

  9. 精尽Spring MVC源码分析 - HandlerAdapter 组件(一)之 HandlerAdapter

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  10. sychronized的实现原理和应用

    一.synchronized的使用 1.1修饰方法 public synchronized void method() { // todo } 1.2修饰代码块 public void run() { ...