当在 Chrome 开发者工具的 Network 面板中看到 GET + Preflight
的 HTTP 请求方法时,意味着该请求涉及跨域资源共享 (CORS),并且该请求被预检了。理解这种请求的背景,主要在于 CORS 的工作机制和现代浏览器对安全性的管理。
下面是在 Chrome 开发者工具 Network 面板里观察到的例子:
什么是 CORS?
CORS 是 Cross-Origin Resource Sharing
的缩写,它是浏览器与服务器之间的一种安全机制,用于控制不同源(如不同域名、端口或协议)之间的 HTTP 请求。正常情况下,浏览器会禁止不同源之间的请求(称为同源策略)。然而,CORS 是一种打破同源策略的方式,允许服务器明确声明哪些源可以访问它的资源。
什么是 Preflight?
Preflight
是 CORS 机制中的一个关键概念。它是一个通过 OPTIONS
方法发出的请求,目的是在执行实际的跨域请求之前,浏览器询问服务器是否允许这个跨域操作。这种请求被称为"预检"请求。浏览器会发起 Preflight
请求,以确保实际的 GET
、POST
等请求可以被安全执行。
预检请求主要是为了处理那些对服务器有潜在影响的"复杂"请求,例如:
- 使用
PUT
、DELETE
方法。 - 使用自定义的 HTTP 头。
下面是自定义 HTTP 请求头部的一个例子:
- 发送 JSON 格式的数据。
通过预检,服务器可以回应是否允许该请求,并指定具体的允许条件,比如允许哪些 HTTP 方法、请求头或返回数据。
为什么会看到 GET + Preflight
?
当你看到 GET + Preflight
,意味着浏览器在发起跨域的 GET
请求时,进行了一个预检请求,以确保服务器允许这个请求。预检请求用 OPTIONS
方法发送,服务器在响应时会指明是否允许后续的跨域请求。
举个例子,假设你有一个前端应用运行在 http://example.com
,而它想要获取一个来自 http://api.example.com
的资源。如果浏览器认为这个请求是一个复杂请求,它就会先发起一个 OPTIONS
请求(即预检),并等待服务器确认是否允许该请求。
示例
场景描述
设想一个跨域 API 请求,前端应用试图从远程 API 获取数据:
javascript
fetch('https://api.example.com/data', {
method: 'GET',
headers: {
'X-Custom-Header': 'CustomValue'
}
});
在这个例子中,由于使用了自定义头 X-Custom-Header
,浏览器会认为这个请求是复杂的,因此需要执行 Preflight
。
预检请求
在这种情况下,浏览器会首先发送一个 OPTIONS
请求去探测目标服务器是否允许该请求。这是典型的预检请求:
http
OPTIONS /data HTTP/1.1
Host: api.example.com
Origin: http://example.com
Access-Control-Request-Method: GET
Access-Control-Request-Headers: X-Custom-Header
服务器响应可能看起来像这样:
http
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: X-Custom-Header
这意味着服务器允许来自 http://example.com
的跨域请求,支持 GET
方法,并且允许使用 X-Custom-Header
请求头。预检请求成功后,浏览器才会继续发送实际的 GET
请求。
一个实际的例子:
实际的 GET
请求
预检成功后,浏览器会发送最终的 GET
请求:
http
GET /data HTTP/1.1
Host: api.example.com
Origin: http://example.com
X-Custom-Header: CustomValue
服务器响应:
http
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: http://example.com
{
"data": "example data"
}
在 Chrome 的 Network 面板中,你会看到这两个请求,分别是 OPTIONS
和 GET
。由于 Preflight
是 GET
请求的一部分,所以你看到的请求被标记为 GET + Preflight
。
使用场合
GET + Preflight
这种情况经常发生在需要跨域请求并且请求较为复杂的场景中。比如:
- 前端应用与不同源的后端 API 通信。
- 微服务架构中,前端可能需要从不同的微服务中获取数据。
- 某些情况下,安全性考虑使得跨域资源访问变得更加严格,比如访问需要认证的资源。
假如没有 Preflight
机制,浏览器的同源策略会限制开发者对外部资源的访问,造成跨域请求无法正常进行。而 Preflight
提供了一个安全的方式,确保跨域请求在得到服务器许可的情况下才会被执行。
如何优化 Preflight 请求?
虽然 Preflight
提供了安全性保障,但额外的 OPTIONS
请求会增加请求的开销,尤其是在高频 API 请求的场景下。开发者可以通过以下方式优化:
-
减少复杂请求 :避免使用自定义的请求头,或者在不必要的情况下使用复杂的 HTTP 方法。比如,简单的
GET
或POST
请求,不使用复杂的头部时,是不需要Preflight
请求的。 -
服务器端优化 :通过设置
Access-Control-Max-Age
头,允许浏览器缓存Preflight
的结果。例如:httpAccess-Control-Max-Age: 600
这表示浏览器可以在 600 秒内不必再次进行预检,从而减少了
Preflight
请求的频率。 -
同源策略优化:在架构设计中,尽量避免跨域请求,尤其是在应用内部组件之间通信时。比如,使用反向代理让所有服务运行在同一域下,避免触发 CORS 机制。
总结
GET + Preflight
请求是现代 Web 应用中非常常见的一部分,它代表了浏览器对跨域请求的安全管理。通过理解 CORS 及其预检机制,开发者可以更好地设计跨域 API 请求,优化应用的性能,同时确保安全性。
在复杂 Web 应用中,特别是 SPA(单页应用)和基于 API 的架构中,跨域请求频繁发生。Preflight
请求的存在可以确保这些跨域操作在安全的前提下进行,同时让开发者能够更灵活地设计前后端分离的架构。