引言

最近在项目中因前后端部署不同地方,前端在请求后端api时发生了跨域请求,我们采用CORS(跨域资源共享)来解决跨域请求,这需要前后端的配合来完成。在这一过程中,后端支持了CORS跨域请求后,前端的请求配置可能会调起CORS的preflight请求,也就是我们所说的预检请求。对CORS不太熟悉的可能会很容易忽视掉这个问题。下面就来说说CORS的preflight请求。CORS的基本用法不在本文讨论中,可以参考阮老师的跨站资源共享CORS详解

CORS prefligt请求

preflight请求,就是在发生cors请求时,浏览器检测到跨域请求,会自动发出一个OPTIONS请求来检测本次请求是否被服务器接受。一个OPTIONS请求一般会携带下面两个与CORS相关的头:

  • Access-Control-Request-Method : 本次预检请求的请求方法。
  • Access-Control-Request-Headers:本次请求所携带的自定义首部字段。这些字段是导致产生OPTIONS请求的一个原因。后面会讲到。

这样,服务端收到该预检请求后,会返回与CORS相关的响应头。主要会包括下面几个,但可能还会有其他的有关CORS字段:

  • Access-Control-Allow-Origin: 服务器允许的跨域请求源
  • Access-Control-Allow-Methods: 服务器允许的请求方法
  • Access-Control-Allow-Headers : 服务器允许的自定义的请求首部字段

服务器通过CORS跨域请求后,下面浏览器就会发生正式的数据请求。整个请求过程其实是发生了两次请求:一个预检请求,通过后的实际数据请求。这些都可以在浏览器网络请求中看到。可以参考下图:

需要注意的是:

1、在上面的两次请求中,预检请求只是一个检查的过程,它不会携带任何请求的参数;预检通过后的请求才会真正的携带请求参数与服务器进行数据通信。

2、若服务器对预检请求没有任何响应,那么浏览器不知道服务器是否支持CORS而不会发送后续的实际请求;或者服务器不支持当前的Origin跨域访问也不会发送后续请求。

发生preflight请求的条件

上面的预检请求并不是CORS请求的必须的请求过程,在一定的条件下并不需要发生预检请求。那么发生预检请求的条件是什么呢?根据HTTP访问控制(CORS)介绍,其实发生预检请求的条件:是否是简单请求。简单请求则直接发送具体的请求而不会产生预检请求。具体来说如下:

满足下面的所有条件就不会产生预检请求,也就是该请求是简单请求:

  • 请求方法是GETPOSTHEAD其中任意一个

  • 必须是下面定义对CORS安全的首部字段集合,不能是集合之外的其他首部字段。

    Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width。

  • Content-Type的值必须是text/plainmultipart/form-dataapplication/x-www-form-urlencoded中任意一个值

满足上面所有的条件才不会发送预检请求,在实际项目中我们的请求格式可能是application/json格式编码,或者使用自定义请求头都会触发CORS的预检请求。

所以,在项目中是否会触发CORS的预检请求要做到心中有数。

一个发送的预检请求的列子

我们拿一个实际发生预检请求的例子来说明整个过程。考虑下面的一个例子:

var xhr = new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/';
var body = '<?xml version="1.0"?><person><name>Arun</name></person>'; function callCors(){
if(xhr)
{
xhr.open('POST', url, true);
xhr.setRequestHeader('X-PINGOTHER', 'pingpong');
xhr.setRequestHeader('Content-Type', 'application/xml');
xhr.onreadystatechange = handler;
xhr.send(body);
}
}
......

上面请求中在请求中添加了自定义首部字段X-PINGOTHER,并且请求的Content-Type值application/xml。因此该请求首先会触发一个预检请求。具体的过程见下图

通过上图可以看到请求实际产生了2次与服务交互的过程,最后一次会将请求参数传给服务器。这样一个CORS请求过程就完成了。

需要注意的一个有关CORS的点:

对于附带身份凭证的请求(即服务器设置Access-Control-Allow-Credentials: true),服务器不得设置 Access-Control-Allow-Origin 的值为“*”。否则请求将会失败。

个人理解是Cookie还是遵循同源策略的,即使因为这个请求是跨域请求,所以每个Origin的Cookie是不能被其他Origin获取到的,也就是不允许Access-Control-Allow-Origin 的值为“*”。

参考文献

1、跨域资源共享 CORS 详解

2、HTTP访问控制(CORS)

3、CORS - How do 'preflight' an httprequest?

CORS预检请求详谈的更多相关文章

  1. ASP Net Core – CORS 预检请求

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

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

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

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

  4. 对CROS OPTIONS预检请求的一些思考

    前后端分离模大势所趋,跨域问题更是老生常谈. 问题背景: 浏览器最基本的安全规范-同源策略.所谓同源是指域名.协议.端口相同.不同源的浏览器脚本(javascript.ActionScript.can ...

  5. OPTIONS预检请求

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

  6. preflight request预检请求

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

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

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

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

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

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

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

随机推荐

  1. C++求出旋转数组的最小数字

    今天遇到这么一道题目,感觉很有意思,要记下来! 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4 ...

  2. html 自定义标签使用实现方法

    通过指定html命名空间的名字来定义自定义标签:默认的一些标签p div等都在html默认的命名空间下.而自定义的标签可以放在自定义的命名空间下,可通过xmlns:命名空间名 来指定,而自定义标签需要 ...

  3. Mongoose之 SchemaTypes 数据类型

    SchemaTypes 数据类型 SchemaTypes handle definition of path defaults, validation, getters, setters, field ...

  4. 【ThinkPHP框架学习 】(2) --- 后台管理系统如何用iframe点击左边右边局部刷新

    如题:         在写后台管理系统时,需要实现后台界面的局部动态刷新.         左边的导航栏使用a标签进行设置,通过href和target属性的配合,就可以将iframe中的子页实现动态 ...

  5. C++雾中风景2:struct还是class?

    之前因为都在忙着毕业的开题答辩与投稿论文的事宜,一直没有时间更新这个系列的文章.师弟看了上一篇雾中风景的文章,希望我继续把这个系列的文章写下去.坦白说,C++的特性很多,这也不是教学指南的文章,我会选 ...

  6. meta 是什么??

    META http-equiv 大全HTTP-EQUIV类似于HTTP的头部协议,它回应给浏览器一些有用的信息,以帮助正确和精确地显示网页内容.常用的HTTP-EQUIV类型有: 1.Content- ...

  7. 对SQL Server事务的4个隔离级别的理解

    事务隔离级别的简单理解   ANSI/ISO SQL标准定义了4种事务隔离级别,这些隔离级别是根据事务并行出现的4个"现象"定义的. 4个现象是: 1.更新丢失(Lost Upda ...

  8. httpwebrequest 用GET方法时报无法发送具有此谓词类型的内容正文

    如下一段小程序,运行结果报无法发送具有此谓词类型的内容正文的错误,其实原因很简单,因为用的是GET的方式进行提交,而GetRequestStream()是用来在post提交的时候写post的内容的流, ...

  9. 下一个计划 : .NET/.NET Core应用性能管理系统

    前言 最近几个月一直在研究开源的APM和监控方案,并对比使用了Zipkin,CAT,Sky-walking,PinPoint(仅对比,未实际部署),Elastic APM,TICK Stack,Pro ...

  10. 0e开头MD5值小结

    s878926199a 0e545993274517709034328855841020 s155964671a 0e342768416822451524974117254469 s214587387 ...