什么是 HTTP 请求中的 preflight 类型请求

在浏览器的 HTTP 请求中,当我们使用 fetch API 或者 XMLHttpRequest 来进行跨域请求时,浏览器有时会发送一种称为 Preflight 的请求。这种请求是浏览器在实际发送跨域请求前,先与目标服务器进行的一次 “探测” 请求,以确认服务器是否允许这样的请求方式。Preflight 请求的存在是为了保障浏览器的安全性,确保跨域请求不会在没有服务器允许的情况下进行。

跨域资源共享(CORS)机制规定了当浏览器发起跨域请求时,某些条件下需要发送 Preflight 请求。这种探测性的请求使用 OPTIONS 方法发出,目标是向服务器询问,客户端接下来想要发送的实际请求是否被允许。
下面是一个例子:

Preflight 请求的触发条件

不是所有的跨域请求都会触发 Preflight 请求,浏览器会根据请求的类型和头部信息来决定是否需要预检。Preflight 请求通常在以下几种情况下触发:

  1. 当请求方法不是 GETPOSTHEAD,例如 PUTDELETE
  2. 当请求包含非标准的 HTTP 头部字段,比如自定义的 Authorization 头部,或者 Content-Type 不是 application/x-www-form-urlencodedmultipart/form-datatext/plain

下面是自定义头部字段触发 preflight 请求的一个例子:

  1. 请求中涉及跨域资源时,尤其是涉及到敏感的操作时,浏览器会通过 Preflight 请求来确保服务器允许这些操作。

这种设计的初衷是为了防止跨域请求滥用,尤其是在涉及敏感数据的场景下,确保浏览器与服务器之间的交互安全。

Preflight 请求的流程

当浏览器决定某个跨域请求需要进行 Preflight,它会先向目标服务器发出一个 OPTIONS 请求,携带一些必要的头部信息,如 Access-Control-Request-MethodAccess-Control-Request-Headers,用于告知服务器,客户端即将发送的请求的具体方法和头部信息。服务器通过响应来告知浏览器,是否允许这样的请求。

请求示例:

假设我们要向 https://api.example.com/data 发送一个跨域的 PUT 请求,并且需要携带自定义头部 X-Custom-Header。在实际发出 PUT 请求之前,浏览器会自动生成如下的 Preflight 请求:

OPTIONS /data HTTP/1.1
Host: api.example.com
Origin: https://client.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header

其中,Access-Control-Request-Method 头部用来告诉服务器接下来会使用 PUT 方法,而 Access-Control-Request-Headers 则表明请求中会携带 X-Custom-Header 这个自定义头部。

服务器响应:

服务器接收到 Preflight 请求后,必须返回一个响应来告诉浏览器是否允许此类请求:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://client.example.com
Access-Control-Allow-Methods: GET, PUT, POST, DELETE
Access-Control-Allow-Headers: X-Custom-Header

服务器通过 Access-Control-Allow-Origin 来指定哪些源是允许访问的(这里是 https://client.example.com),通过 Access-Control-Allow-Methods 来列出允许的 HTTP 方法,并通过 Access-Control-Allow-Headers 来列出允许的头部字段。
下面是 Preflight 请求来自服务器端的响应的一个例子:

Preflight 请求的使用场合

Preflight 请求主要用于跨域场景下,特别是那些涉及到更复杂请求的场合,比如非 GETPOST 方法,或者请求中包含了额外的自定义头部。

常见的使用场景包括:

  1. RESTful API 请求:当前端应用需要与其他域名下的 REST API 进行交互时,尤其是对资源进行 PUTDELETE 操作时,往往会触发 Preflight 请求。这些操作可能会修改服务器上的数据,因此需要确保安全。

    例如,一个前端应用需要向远程服务器发送数据更新请求,使用 PUT 方法更新用户信息。在这种场景下,Preflight 请求就会确保目标服务器允许跨域的 PUT 请求。

  2. 上传文件的操作:在表单上传文件时,如果使用 fetch API 或 XMLHttpRequest 并携带了非标准的头部,比如自定义的认证信息,通常会触发 Preflight 请求。浏览器需要确保服务器允许上传操作以及这些自定义的头部字段。

  3. 自定义认证头部的请求:很多应用在发起跨域请求时,需要在头部中携带如 AuthorizationToken 的自定义认证信息。由于这些头部字段并非标准字段,浏览器会先发送 Preflight 请求来探测服务器是否允许使用这些自定义头部。

Preflight 请求的实际案例

在实际开发中,有一个典型的例子是前端应用需要向第三方服务发送请求并带有认证信息。这种场景下的跨域请求常常会触发 Preflight 请求。

假设我们开发了一个电子商务应用,这个应用的后端服务托管在 https://api.shop.com,而前端页面托管在 https://shop.com。用户在购物时,前端需要向后端发送带有用户身份认证的请求,如以下场景:

  1. 用户在购物车页面点击结账,前端应用需要向后端 API 发送包含用户认证信息的请求,以确认用户是否已登录,且是否有购买权限。
  2. 请求方法为 POST,同时头部中带有 Authorization: Bearer token123 来验证用户身份。

此时,由于 Authorization 头部是非标准字段,且前端和后端的域名不同,这个请求会触发 Preflight 检查。

请求步骤:
  1. Preflight 请求
    浏览器会自动先发送一个 OPTIONS 请求,探测服务器是否允许发送带有 Authorization 头部的跨域请求:

    OPTIONS /checkout HTTP/1.1
    Host: api.shop.com
    Origin: https://shop.com
    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: Authorization
    
  2. 服务器响应
    后端服务器接收到该请求后,会检查是否允许该跨域请求,并返回允许的结果:

    HTTP/1.1 204 No Content
    Access-Control-Allow-Origin: https://shop.com
    Access-Control-Allow-Methods: POST
    Access-Control-Allow-Headers: Authorization
    

    响应中,服务器明确告知浏览器允许该域名 https://shop.com 发起 POST 请求,并且允许使用 Authorization 头部。

  3. 实际请求
    在确认服务器允许跨域请求后,浏览器会继续发送实际的 POST 请求,包括认证信息:

    POST /checkout HTTP/1.1
    Host: api.shop.com
    Origin: https://shop.com
    Authorization: Bearer token123
    
使用 Preflight 请求的优化

尽管 Preflight 请求保障了安全性,但在一些频繁的跨域请求场景下,这会带来额外的网络开销。为此,可以采用一些优化策略:

  1. 服务器缓存 Preflight 响应:通过在响应中设置 Access-Control-Max-Age 头部,服务器可以告知浏览器在一定时间内不需要重复进行 Preflight 请求。这能显著减少不必要的 OPTIONS 请求,提升应用的性能。

    例如,服务器可以返回这样的响应,告知浏览器在未来 10 分钟内不需要重新发起 Preflight 请求:

    HTTP/1.1 204 No Content
    Access-Control-Allow-Origin: https://shop.com
    Access-Control-Allow-Methods: POST
    Access-Control-Allow-Headers: Authorization
    Access-Control-Max-Age: 600
    
  2. 减少复杂的请求:避免不必要的自定义头部字段,或者尽量使用简单的 GETPOST 请求,能够有效减少 Preflight 请求的触发。对于一些轻量级的操作,使用标准的请求方法和头部可以避免 Preflight 请求,从而提升效率。

结语

Preflight 请求作为 CORS 机制的一部分,主要作用是确保跨域请求的安全性,尤其是在涉及非标准请求时。通过 Preflight 请求,浏览器与服务器能够就请求的合法性达成共识,保护用户的数据安全。在实际应用中,理解 Preflight 请求的工作原理,并在合适的场景下进行优化,能够大大提升 Web 应用的性能和用户体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/440261.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

组合式API

1.入口&#xff1a;setup setup中的数据和方法必须return出去&#xff0c;模板才能使用 <script> export default {setup () {console.log(setup);const message this is a messageconst logMessage () > {console.log(message);}return {message,logMessage}},be…

Visual Studio 2017编译libexpat源码过程

一、编译环境 操作系统&#xff1a;Windows 10 企业版 64位 编译工具&#xff1a;Visual Studio 2017 构建工具&#xff1a;CMake3.22 源码版本&#xff1a;libexpat-R_2_4_0 二、CMake生成解决方案 解压libexpat源码&#xff0c;然后启动CMake选择libexpat源码目录&#xff1…

数据结构 ——— 单链表oj题:链表的回文结构

目录 题目要求 手搓简易单链表 代码实现 题目要求 对于一个单链表&#xff0c;设计一个时间复杂度为O(N)&#xff0c;空间复杂度为O(1)的算法&#xff0c;判断其是否为回文结构&#xff0c;给定一个链表的头指针 head&#xff0c;返回一个 bool 值&#xff0c;代表其是否为…

从认识String类,到走进String类的世界

作为一个常用的数据类型&#xff0c;跟随小编一同进入String的学习吧&#xff0c;领略String的一些用法。 1. 认识 String 类 2. 了解 String 类的基本用法 3. 熟练掌握 String 类的常见操作 4. 认识字符串常量池 5. 认识 StringBuffer 和 StringBuilder 一&#xff1a;…

Selenium WebDriver和Chrome对照表

PS&#xff1a;我的没下载WebDriver 也没配置环境变量 也能用Selenium 网上有说把WebDriver放到chrome的安装目录并将路径配到path中【可能之前用playwright下载过】 查看浏览器版本号 在浏览器的地址栏&#xff0c;输入chrome://version/&#xff0c;回车后即可查看到对应版…

文心一言 VS 讯飞星火 VS chatgpt (363)-- 算法导论24.3 5题

五、Newman 教授觉得自己发现了 Dijkstra 算法的一个更简单的证明。他声称 Dikstra 算法对最短路径上面的每条边的松弛次序与该条边在该条最短路径中的次序相同&#xff0c;因此&#xff0c;路径松弛性质适用于从源结点可以到达的所有结点。请构造一个有向图来说明 Dijkstra 算…

SpringBoot基础(四):bean的多种加载方式

SpringBoot基础系列文章 SpringBoot基础(一)&#xff1a;快速入门 SpringBoot基础(二)&#xff1a;配置文件详解 SpringBoot基础(三)&#xff1a;Logback日志 SpringBoot基础(四)&#xff1a;bean的多种加载方式 目录 一、xml配置文件二、注解定义bean1、使用AnnotationCon…

逻辑回归(下): Sigmoid 函数的发展历史

背景 闲来无事翻了一下之前买的一个机器学习课程及之前记录的网络笔记&#xff0c;发现遇到公式都是截图&#xff0c;甚至是在纸上用笔推导的。重新整理一遍之前逻辑回归函数的学习笔记&#xff0c;主要是为了玩一下 LaTex 语法&#xff0c;写公式挺有意思的。 整理之前三篇笔…

鸿蒙harmonyos next flutter通信之MethodChannel获取设备信息

本文将通过MethodChannel获取设备信息&#xff0c;以此来演练MethodChannel用法。 建立channel flutter代码&#xff1a; MethodChannel methodChannel MethodChannel("com.xmg.test"); ohos代码&#xff1a; private channel: MethodChannel | null nullthis.c…

使用JavaScript写一个网页端的四则运算器

目录 style(内联样式表部分) body部分 html script 总的代码 网页演示 style(内联样式表部分) <style>body {font-family: Arial, sans-serif;display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #f0f0f0;}.calculator {…

Pikachu-目录遍历

目录遍历&#xff0c;跟不安全文件上传下载有差不多&#xff1b; 访问 jarheads.php 、truman.php 都是通过 get 请求&#xff0c;往title 参数传参&#xff1b; 在后台&#xff0c;可以看到 jarheads.php 、truman.php所在目录&#xff1a; /var/www/html/vul/dir/soup 图片…

golang gin入门

gin是个小而精的web开发框架 官方文档 安装 go get -u github.com/gin-gonic/gin最简单的起手代码 package mainimport ("net/http""github.com/gin-gonic/gin" )func main() {r : gin.Default()r.GET("/ping", func(c *gin.Context) {c.JSON…

openpnp - 图像传送方向要在高级校正之前设置好

文章目录 openpnp - 图像传送方向要在高级校正之前设置好笔记图像传送方向的确定END openpnp - 图像传送方向要在高级校正之前设置好 笔记 图像传送方向和JOG面板的移动控制和实际设备的顶部摄像头/底部摄像头要一致&#xff0c;这样才能和贴板子时的实际操作方向对应起来。 …

大数据新视界 --大数据大厂之 从 Druid 和 Kafka 到 Polars:大数据处理工具的传承与创新

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【Vue】vue-admin-template项目搭建

准备 node环境 node&#xff1a;v16.12.0npm&#xff1a;8.1.0 vue-element-admin下载 官网&#xff1a;https://panjiachen.github.io/vue-element-admin-site/guide/ 我这边下载的是4.4.0版本的&#xff0c;使用其他版本可能会因为所需要的node和npm版本过低或过高导致异常…

【包教包会】2D图片实现3D透视效果(支持3.x、支持原生、可合批)

将去年写的SpriteFlipper从2.x升级到3.x。 如果需要2.x版本或需要了解算法思路&#xff0c;请移步&#xff1a;https://blog.csdn.net/weixin_42714632/article/details/136745051 优化功能&#xff1a;可同时绕X轴和Y轴旋转&#xff0c;两者效果会叠加。 完美适配Web、原生…

Gridview配置数据源--信任服务器证书

目录 背景过程Gridview配置数据源GridView与数据源&#xff1a;数据库连接与安全&#xff1a;信任服务器证书&#xff1a;配置信任服务器证书&#xff1a;注意事项&#xff1a; 生成连接字符串程序运行报错问题解决 总结 背景 Gridview配置数据源之后&#xff0c;程序报错 过…

k8s的pod的管理和优化

资源管理介绍 在kubernetes中&#xff0c;所有的内容都抽象为资源&#xff0c;用户需要通过操作资源来管理kubernetes。 kubernetes的本质上就是一个集群系统&#xff0c;用户可以在集群中部署各种服务 所谓的部署服务&#xff0c;其实就是在kubernetes集群中运行一个个的容器…

C++ | Leetcode C++题解之第456题132模式

题目&#xff1a; 题解&#xff1a; class Solution { public:bool find132pattern(vector<int>& nums) {int n nums.size();vector<int> candidate_i {nums[0]};vector<int> candidate_j {nums[0]};for (int k 1; k < n; k) {auto it_i upper_…

动态规划基础一>面试题 08.01. 三步问题

1.题目&#xff1a; 2.解析&#xff1a; 代码&#xff1a; public int waysToStep(int n) {/**1.创建dp表2.初始化3.填表4.返回值*/int MOD (int)1e9 7;//注意不能超出int范围&#xff0c;每做一次操作要取模//处理边界情况if(n 1 || n 2) return n;if(n 3) return 4;//1…