引言

最近在项目中因前后端部署不同地方,前端在请求后端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?

转载于:https://www.cnblogs.com/wonyun/p/CORS_preflight.html

CORS预检请求详谈相关推荐

  1. php 405跳转,php – 返回HTTP 405的CORS预检请求

    我正在尝试创建一个RESTful Web服务,并且已经停止实现PUT请求.我尝试过但未能在本网站上关注其他答案以及Mozilla的各种文章. 该请求是从域wwwtest.dev-box生成的,它将转到 ...

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

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

  3. OPTIONS预检请求

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

  4. Chrome98和Chrome101的跨域变化,httpOPTIONS预检请求,私有网络访问限制

    在Chrome94更新时,发现访问本地服务器的时候谷歌浏览器限制了访问本地资源 当时通过一个浏览器设置进行了处理.但是治标不治本,98版本更新后又出现了CORS跨域问题.查询了一下资料: Chrome ...

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

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

  6. 对CORS OPTIONS预检请求的一些思考

    前后端分离模大势所趋,跨域问题更是老生常谈. <程序员应对浏览器同源策略的姿势>一文提到三种跨域请求方案,重点讲述了w3c和浏览器厂商推出的CORS规范. 同源策略  所谓同源是指域名.协 ...

  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. 从前后端的角度分析options预检请求——打破前后端联调的理解障碍

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

最新文章

  1. PHP利用jpgraph类画折线图
  2. 语言结构体在内存的分布_结构体内存对齐,这篇文章给你彻底搞会!(干货收藏)...
  3. HashMap Hashtable区别
  4. fb 4.7英文版 显示行数
  5. 【重难点】【Java基础 05】说一说你平时遇到的异常、什么情景下会用到反射、反射的底层原理
  6. 好酷啊,真是图片吗?
  7. Java aio(异步网络IO)初探
  8. 数据集的非均衡问题(imbalanced data)和应对方法
  9. 列车运行图的编制原则是什么_列车运行图编制规则
  10. python视频车流量计数_【使用攻略】【图像识别】车流量统计(动态版)
  11. 浅谈软件项目验收(转)
  12. AllenNLP—笔记—TokenEmbedder
  13. 高通QCC3005_datasheet
  14. 魔兽世界单机mysql修改怪物血量_魔兽世界单机版如何修改怪物掉落物品个数
  15. 针对豆瓣TOP250电影知识图谱的构建(Python+neo4j)
  16. 百度地图批量精度和维度Java,关于百度地图API批量转换成坐标的方法
  17. python 白噪声检验-时间序列 平稳性检验 白噪声 峰度 偏度
  18. 区块链已成主流,BATJ纷纷加速布局
  19. Linux SDIO WIFI Marvell8801/Marvell88w8801(八) --- Marvell Linux Wi-Fi driver 对接芯片上行下行接口介绍
  20. linux 安装水星无线网卡驱动,Linux下安装RTL8188CE网卡驱动(Mercury MW150U)

热门文章

  1. python从入门到大神系列手机_python从入门到大神---2、和Python编程相遇的日子
  2. Vue项目中 css样式的作用域(深度作用选择器)
  3. LeetCode 1750. 删除字符串两端相同字符后的最短长度(双指针)
  4. 牛客 牛牛浇树(差分)
  5. 程序员面试金典 - 面试题 10.11. 峰与谷(排序/不排序)
  6. 【机器学习-数据科学】第一节:numpypandas
  7. cron 每周一执行_详解定时任务中的 cron 表达式
  8. python——作用域 == is
  9. 解决The total number of locks exceeds the lock table size错误
  10. python 时间函数 毫秒_利用python进行播放音频与录音,骚操作!