什么是预检请求?CORS 检查详解
Scrapeless Agent Browser 运行基于浏览器的工作流,其中目标页面仍然受浏览器跨源请求规则的约束。
摘要
- CORS 预检用于检查拟进行的跨源请求是否被允许。 浏览器会在某些应用请求之前发送一个 OPTIONS 请求。
- OPTIONS 成功状态本身并不足够。 浏览器必须根据拟进行的操作验证所需的 CORS 字段。
- CORS 权限不会取代 API 授权。 资源服务器仍然会检查凭证和操作权限。
- 命令行请求成功并不能证明浏览器能访问。 浏览器的同源策略增加了服务器端 HTTP 客户端不会强制执行的检查。
预检是在询问一个拟进行的浏览器请求
CORS 预检是浏览器发送的 HTTP OPTIONS 请求,用于检查服务器是否允许特定的跨源请求。它描述调用方的源、预期使用的方法以及相关的请求字段名。如果服务器的响应满足浏览器的检查,浏览器才能继续执行应用请求。预检是浏览器访问模型中的权限协商,而不是应用操作本身。
该 Fetch Standard CORS model 定义了这种行为。一个 origin 由 scheme、host 和 port 决定,因此即使两个 URL 的域名看起来非常相近,也可能属于不同的 origin。从一个 origin 提供的前端和从另一个 origin 提供的 API,可能需要进行 CORS 配置,浏览器中的 JavaScript 才能访问该 API 的响应。
CORS 是 Cross-Origin Resource Sharing(跨源资源共享)的缩写。它允许服务器在同源安全模型内选择加入某些跨源浏览器交互。策略由浏览器强制执行,而服务器通过响应字段声明自己允许的内容。应用无法通过在自身发出的请求中添加响应权限字段来解决被拒绝的跨源请求。
并非每个跨源请求都需要预检
有些跨源请求符合 CORS 安全列入(safelisted)的方法和字段规则,因此不需要预检。具体条件包括方法、请求字段值以及相关的 Fetch 行为。带有非安全列入字段的 GET 请求可能需要预检,而满足约束条件的 POST 则可能不需要。因此,仅凭方法名是不完整的决策依据。
常见触发条件包括使用安全列入集合之外的方法、包含 Authorization 字段,以及使用不在安全列入媒体类型中的 JSON 内容类型。这些示例解释了许多浏览器网络跟踪中的现象,但完整的判断属于 Fetch 规则的范围。不要把所有 GET 都描述为简单请求,也不要把所有 POST 都描述为必经预检的请求。请检查实际的请求配置。
这篇 browser preflight request explanation 区分了前置的 OPTIONS 请求与真实请求。服务器可能会收到一些不需要预检的请求,而浏览器仍然会拒绝向 JavaScript 暴露其响应。因此,不应把 CORS 描述为阻止每一个跨源请求到达服务器的通用屏障。
浏览器会描述预期使用的方法和字段
预检请求包含 Origin,用于标识调用方的源。Access-Control-Request-Method 标明浏览器打算在实际请求中使用的方法。Access-Control-Request-Headers 列出需要权限的相关请求字段名。这些是对拟进行操作的描述;它们并不意味着 OPTIONS 请求本身执行了该操作或携带了应用的完整负载。
服务器通过响应字段描述允许的源、方法和请求字段(如适用)。浏览器会根据拟进行的请求来评估这些声明。当通用的 OPTIONS 处理程序省略了所需权限或授予了不同的方法时,就不够用。请保持精确比对,以便诊断出策略中哪一部分失败。
| 字段 | 方向 | 在交互中的含义 |
|---|---|---|
| Origin | 浏览器请求 | 调用页面的源 |
| Access-Control-Request-Method | 预检请求 | 为应用请求所提议的方法 |
| Access-Control-Request-Headers | 预检请求 | 需要权限的请求字段名 |
| Access-Control-Allow-Origin | 服务器响应 | 服务器允许访问的源 |
| Access-Control-Allow-Methods | 预检响应 | 允许的请求方法 |
| Access-Control-Allow-Headers | 预检响应 | 允许的请求字段名 |
| Access-Control-Max-Age | 预检响应 | 用于缓存预检结果的允许存活时间 |
应用请求仍然是一个单独的交互。一旦到达,API 会验证其凭据、参数和权限。其响应同样需要包含适当的 CORS 字段以供浏览器访问。通过预检检查并不意味着后续未授权或格式错误的应用操作会成功,也不会让实际响应免于遵守来源策略处理。
凭据使来源配置更为具体
带凭据的浏览器请求要求 CORS 响应策略与凭据模式和请求来源相匹配。在暴露带凭据的响应时,不能用通配符允许的来源来普遍替代明确指定的来源。服务器还需要具备相应的凭据许可。应从受控的来源策略中配置这些字段,而不是在未经检查的情况下反射任意输入。
Cookie 引入了超出 CORS 之外的附加规则。一个请求可以满足其 CORS 策略,同时 Cookie 投递却受 Cookie 属性或浏览器隐私行为的限制。反过来,Cookie 的存在并不表明服务器已经接受了该会话。将 Cookie 投递、CORS 暴露和应用授权视为相互独立的诊断问题。
该 CORS 凭据与响应字段指南 涵盖了这些交互。根据标准模型,即使拟议的应用请求是带凭据的,预检通常也不包含凭据。要求每个 OPTIONS 请求都具有登录会话的中间件,因此可能会在评估已授权的应用请求之前就阻断协商。
预检失败与 API 调用失败是两回事
预检失败可能会阻止浏览器发送拟议的应用请求。在这种情况下,API 路由的日志中可能没有对应的应用操作,而网关记录了 OPTIONS。诊断应从确定实际发生的是哪一种交互开始。控制台中的通用 CORS 错误本身并不能表明是路由、字段策略、凭据还是实际响应导致了问题。
如果应用请求确实到达了服务器,请检查其自身的状态和 CORS 响应字段。服务可能会返回一个有用的错误主体,但由于错误响应遗漏了来源许可,浏览器 JavaScript 无法读取它。在保持正常 API 授权的同时,将预期的 CORS 策略一致地应用到支持的成功和错误响应上。不要把每次失败都变成对来源允许列表的修改。
OPTIONS 请求并不总是 CORS 预检。HTTP 更广泛地将 OPTIONS 定义为关于目标资源通信选项的请求。 HTTP OPTIONS 语义 以及 CORS 请求字段的存在,有助于区分浏览器预检与手动发起的 OPTIONS 请求或其他基础设施检查。应诊断实际存在的请求,而不是仅根据其方法名。
预检缓存有其自身的生命周期
浏览器可以根据适用规则(包括 Access-Control-Max-Age 和实现限制)缓存一次成功的预检许可。该缓存不同于普通的应用响应内容缓存。它可以解释为什么后续请求看起来没有新的 OPTIONS 交互。在一次跟踪中缺少预检并不能证明该请求永远不需要预检。
缓存范围还取决于请求上下文、来源、目标、方法和字段权限。一次针对某个路由或字段集的成功检查,并不对该主机上的所有操作给出一揽子批准。在调试时,记录拟议的方法和请求字段以及目标 URL。比较缺少这些细节的跟踪会让正常的策略差异看起来不一致。
对不同调用者返回不同来源许可的服务器,应将中间缓存行为考虑在内。 HTTP 缓存选择规则 解释了如何表达响应差异以防止不当复用。当应用响应会因 Origin 而变化时,应配置相关的缓存变体,而不是允许一个调用者声明的来源被不加区分地复用于另一个调用者。
从来源到应用调试整条交互
从调用页面的完整来源以及最终的 API 目标开始。检查重定向或网关是否对 OPTIONS 与应用方法采用了不同路由。将拟议的方法和字段与服务器的显式策略进行比较。然后检查实际请求是否到达,以及其响应是否包含预期的 CORS 字段。该流程可以定位失败点,而不必不加区分地削弱策略。
命令行客户端有助于检查 HTTP 响应,但它本身并不会重现浏览器的 CORS 执行行为。从后端进程发出的请求成功,只能证明该进程在其自身的网络和凭据上下文中获得了响应。浏览器仍会评估来源规则。将客户端改成一种隐藏响应的模式,并不会产生读取受保护响应内容的权限。
保持诊断信息脱敏。授权值和 Cookie 不应粘贴到共享的跟踪中。通常字段名、来源、路由、方法、状态以及权限字段值就足以解释一次 CORS 不匹配。如果应用涉及个人记录,只捕获授权调查所必需的最少内容,并将该捕获限制在适当的访问边界内。
浏览器自动化仍然遵循来源模型
Scrapeless Agent Browser 提供了一个用于自动化导航和交互的浏览器环境。它不会改变目标页面的跨来源应用约定。 Agent Browser 概览 描述的是浏览器的能力,而页面和 API 所有者仍然对来源策略以及授予调用方的权限负责。将浏览器控制连接与在目标页面内执行的 JavaScript 分离开来。到云浏览器的自动化客户端连接与页面脚本访问跨来源 API 是不同的网络交互。控制通道的成功并不能证明页面的 API 调用已经通过了 CORS。解释页面能够访问什么时,应观察目标请求及其对应的响应。
结论 Fetch 请求工作流 是与 HTTP 客户端相关的延伸阅读,而 Scrapeless pricing 涵盖浏览器服务的使用。对于一次授权测试,定义预期的来源、操作以及可见的页面结果。一次通过的浏览器观测应同时确认策略交换和由此产生的应用行为,而不是在 OPTIONS 状态处就停下来。
结论
预检会在某些浏览器请求继续之前,评估一个特定的拟议跨来源操作。检查调用来源、方法、字段名称、凭据模式以及两个响应。将浏览器权限检查与 API 授权分开,并在拥有失败交换的那个组件上诊断策略问题。
构建你的 Web 数据工作流
使用 Agent Browser 观察被允许的页面工作流,并在实际的目标请求边界验证跨来源行为。
立即注册即可获得 $5 in free credit — 无需信用卡.
领取你的 $5 额度 →常见问题
是否每个跨来源请求都需要预检?
并非每个跨来源请求都需要预检。浏览器会评估方法、请求字段及其值,以及适用的 Fetch 规则。即使没有预检,请求的跨来源响应仍然需要适当的 CORS 响应许可,JavaScript 才能访问。
HTTP 200 的 OPTIONS 是否能证明 CORS 正确?
OPTIONS 返回 HTTP 200 并不能证明 CORS 正确。浏览器还会检查允许的来源、方法、字段以及凭据要求。在初步交换成功后,实际的应用响应必须通过它自身的 CORS 检查。
CORS 是一个认证系统吗?
CORS 不是一个认证系统。它管理浏览器代码的跨来源访问。API 必须单独验证凭据并强制执行资源权限,包括对那些未实现浏览器来源策略检查的客户端。
为什么一个 API 在后端可用,但在浏览器中失败?
一个 API 可以在后端可用,却在浏览器中失败,因为浏览器 JavaScript 必须满足同源和 CORS 规则。还要对比凭据、最终 URL 和请求字段;这两个客户端可能没有发送等效的请求。
为什么在后续的网络追踪中没有 OPTIONS 请求?
后续的追踪可能省略 OPTIONS,因为请求不再需要预检,或者有效的预检权限已经被缓存。在下结论前请比较完整的请求上下文。应用响应缓存与预检权限缓存是不同的机制。