什么是 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 请求:

http 复制代码
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 复制代码
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 头部的跨域请求:

    http 复制代码
    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 复制代码
    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 请求,包括认证信息:

    http 复制代码
    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 复制代码
    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 应用的性能和用户体验。

相关推荐
大熊背22 分钟前
双目拼接中色差消除优化
网络
Sagittarius_A*26 分钟前
Command Injection 命令注入漏洞:系统命令拼接缺陷与执行利用技术
网络·安全·web安全·dvwa·命令注入漏洞
Tsuki_tl28 分钟前
【面试高频】HTTPS加密传输过程
http·https·非对称加密·数字证书·对称加密·ca证书·中间人攻击
tiantianuser39 分钟前
NVME-oF IP 设计7 :设计扫盲5
网络协议·rdma·roce v2·nvme of
ShineWinsu39 分钟前
对于Linux:TCPsocket编程基础的解析
linux·网络协议·tcp/ip·面试·笔试·进程·远程指令
曙光_deeplove1 小时前
海康機器人工業相機(丢失帧、空帧和残帧/不完整帧)
网络
Android洋芋2 小时前
漏洞挖掘与赏金攻略
网络·安全·web安全
王燕龙(大卫)2 小时前
fastdds笔记
网络·c++·笔记
meilindehuzi_a2 小时前
浏览器端 HTTP 流式通信详解:从 SSE 到 EventSource、fetch 与 ReadableStream
网络·网络协议·http
数据知道2 小时前
SDN 与软件定义网络的安全边界在哪里?
网络·安全·网络安全