人工智能前沿

2026 年 macOS 上 OpenClaw 网关的 CORS 与 OPTIONS 预检:允许源、凭据、nginx 边缘响应头与云 Mac mini 演练

MacHTML Lab2026.05.15约 33 分钟阅读

当产品团队把浏览器控制台或内部单页应用接到监听 TCP 8787OpenClaw 网关时,2026 年最常见的“神秘故障”往往不是模型接口,而是 CORScurl 能通,Safari 与 Chrome 却提示 blocked by CORS policy,通常是因为浏览器发出的 OPTIONS 预检在边缘未被正确处理,或因为响应里写了 Access-Control-Allow-Origin: * 而前端使用了 credentials: 'include'。本文给出显式源白名单、简单与带凭据请求的差异、nginx 上响应头顺序与重复头陷阱,以及可直接贴进工单的 curl 探针,并与 首次运行 PATH、Node 与 LaunchAgent 冒烟端口占用与健康探针对齐doctor 网关诊断 对齐,减少跨团队扯皮。

读完你会得到决策表、响应头配方、数值护栏(204200 的 OPTIONS 均可接受;带凭据时 禁止通配符),以及 MacHTML 公开定价上接近 每日约 16.9 美元 的租用基线,便于在与客户相同的 Safari 版本上复现问题。

浏览器与 curl 的差异

curl https://gateway.example/health 只能证明可达性,不能证明浏览器策略。用户代理在跨站调用时会附加 Origin,在出现自定义头时可能把原本简单的 GET 变成需要预检的 POST,并且除非 Access-Control-Allow-Origin 与发起源匹配(或非凭据场景下为 *),否则拒绝把响应体暴露给 JavaScript。把 CORS 视为前端与平台的双边合同:前端负责给出精确的源字符串;平台负责在终结 TLS 的那一跳按正确顺序发出响应头。

请用「协议 + 主机 + 端口」记录每个调用方——https://app.corp.internal:8443https://app.corp.internal 不是同一个源。白名单漏写端口会导致仅在非默认 TLS 端口的预发环境间歇失败。这也是许多团队在专用 Mac mini 上与高管笔记本相同 Safari 版本做演练的原因。

简单请求与带凭据请求

不含自定义头的简单 GET 可能跳过预检,但若 JavaScript 需要跨源读取响应体,仍需要正确的 Access-Control-Allow-Origin。一旦加入 AuthorizationCookiefetch(..., { credentials: 'include' }),规范要求回显具体源——不允许通配符,并应配合 Access-Control-Allow-Credentials: true

若仅暴露匿名指标,可全程使用 * 并避免 Cookie。混合模式——部分路由带凭据、部分匿名——应用 nginx 的 location 拆分,避免营销像素误继承管理后台的 CORS 头。

OPTIONS 预检机制

预检会发送 OPTIONS,并携带 Access-Control-Request-Method 与可选的 Access-Control-Request-Headers。网关必须以 Access-Control-Allow-Methods 列出允许的动词(常见为 GET,POST,OPTIONS),以 Access-Control-Allow-Headers 按大小写不敏感方式回显所请求的头名,并可用 Access-Control-Max-Age 让浏览器缓存握手——开发期常用 300 秒,生产环境视头轮换频率取 600–86400

返回 204 无正文或 200 空正文均可。失败形态包括 405 Method Not Allowed(nginx 把 OPTIONS 路由到错误上游),或在动态回显源时缺少 Vary: Origin 导致 CDN 把错误的 ACAO 缓存给所有租户。

源白名单与 localhost 陷阱

http://localhost:5173(Vite)与 http://127.0.0.1:5173 是不同的源。本地开发应同时加入,或统一 dev 命令只使用一种主机名。SSH 本地转发把 127.0.0.1:8787 暴露给工程师笔记本时,浏览器的源仍是线上 SPA 的公网 URL,而不是回环跳——白名单必须包含 SPA 的源,而不是只写 http://127.0.0.1

动态反射——把任意入站 Origin 原样写进 Access-Control-Allow-Origin——省事但危险,除非服务端用固定集合校验。推荐映射表:若源属于集合 S 则回显,否则省略该头让浏览器失败闭合。对被拒绝的源以 INFO 级别抽样记录,安全团队可审计滥用而不撑爆磁盘。

nginx 与重复响应头

nginx 终结 TLS 并把流量转发到本机 OpenClaw 时,要明确 CORS 由 nginx 还是 Node 进程负责——两处都加会产生重复头,部分浏览器直接拒绝。务实拆分:nginx 处理静态资源与营销页;若网关已为 CLI 兼容性发出 API 头,则可仅由 OpenClaw 处理 API 路由。无论选哪条路径,都要写进与优雅停机同一本运行手册,避免事故中“各修一遍 CORS”。

若在 nginx 终结 HTTP/2,注意旧版配置里 add_header 可能只在 2xx 附加头,除非使用 always。OPTIONS 落到错误 server 块是 SPA 神秘失败的第二大原因,仅次于通配符与凭据不匹配。

Vary: Origin、CDN 缓存与陈旧 ACAO

当你按请求回显源时,响应在语义上随 Origin 变化。若缺少 Vary: Origin,中间缓存可能把甲客户的 Access-Control-Allow-Origin 喂给乙客户的会话——既是隐蔽的数据泄漏,也是功能性 bug。部分 CDN 会激进规范化响应头并剥离 Vary;若边缘规则改写 CORS,应向供应商开工单。

调试 CORS 时把缓存错误体的 TTL 调到 60 秒以内,避免坏发布在边缘挂数小时。把缓存清理与结构化日志里的关联 ID 结合,即便用户打码截图,也能把 HAR 与网关日志对齐。

JWT、自定义头与工具路由

OpenClaw 工具路由常附加 X-Request-IdX-OpenClaw-Profile 风格的头。任何非浏览器安全列表内的头都会触发预检,必须在 Access-Control-Allow-Headers 中显式枚举——带凭据流程不能指望 *。若 JWT 走 Authorization: Bearer,请确认预检与真实 POST 返回的 ACAO 行一致;不一致时会出现“CORS 策略已阻止……没有 Access-Control-Allow-Origin 头”的经典报错,即便服务端已处理 POST。

轮换签名密钥时,可临时把预检缓存窗口加倍,使浏览器在 15 分钟 内拾取新头名,再收紧 max-age,并与 TLS 证书续期日历写在同一运维看板。

决策矩阵

调用方是否带凭据ACAO 策略备注
公开文档站* 或静态白名单保持匿名;不使用 Cookie
内部管理 SPA回显具体源配合 Allow-Credentials: true
移动 WebView有时自定义 scheme 源校验 WebView URL 模式
第三方 SaaS 嵌入少见静态合作伙伴源仅以合同白名单为准

可归档的 curl 探针

# 预检(替换主机与路径)
curl -i -X OPTIONS "https://gw.example/v1/chat" \
  -H "Origin: https://app.example" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: authorization,content-type"

# 带 Origin 的简单 GET,验证 GET 上的 ACAO
curl -i "https://gw.example/health" \
  -H "Origin: https://app.example"

把完整响应头存进工单,每次发布后做 diff。当边缘 OPTIONS 的 p95 延迟超过 150 ms 而 GET 健康检查仍在 12 ms 量级,应优先排查路由到冷上游,而不是先指责 OpenClaw 本体。

上线检查清单

  1. 枚举生产与预发 SPA 的每个源,包含协议、主机与端口。
  2. 确定 CORS 头的唯一责任方——nginx 或 OpenClaw——并移除重复。
  3. 在 CI 中用与本地一致的 Origin 字符串运行 OPTIONS 探针。
  4. 用自动化测试验证带凭据流程拒绝通配符 ACAO。
  5. 修改端口或响应头后重跑 openclaw doctor;确认健康端点仍为 200
  6. 在租用的 mini 上抓取 Safari 与 Chrome 的 HAR,保留 90 天

越来越多的安全评审要求证明动态源反射有上界;把白名单文件纳入 git 并由平台团队 CODEOWNERS,可防止“临时通配符”提交变成永久攻击面。

常见问题

为何 Safari 失败而 Chrome 正常?

Safari 对重复 CORS 头与混合内容更严格;请在真实 macOS 硬件上双引擎验证。

预检应永久缓存吗?

不应——使用有界的 Access-Control-Max-Age,使头轮换在分钟到小时级传播,而非数周。

WebSocket 是否遵循相同 CORS 规则?

握手是带 Origin 头的 HTTP 升级;请用与 REST 相同的白名单逻辑校验。

Apple Silicon Mac mini 租用可让你在决策者与投资人常用的 Safari / WebKit 栈上演示网关面板。MacHTML 云节点支持用 SSH 跑脚本化 curl 套件,也可选配 VNC 让设计师实时查看 Network 面板。空闲功耗常在 12 W 量级,把一台演练 mini 开一整周的成本,通常低于把错误 CORS 头推到生产再在董事会演示时回滚。

租用还能绕开重资产采购周期:按公开定价页约 每日 16.9 美元 计费,而不必再买一台集成结束后长期闲置的实体机。CORS 工作结束后停实例即可;响应头留在 git,硬件不会在账上跨 36 个月 折旧。

在真实 macOS 网关上演练 OpenClaw CORS

租用云 Mac mini,在合并网关改动前用 Safari 验证 OPTIONS、带凭据请求与 nginx 边缘响应头。

CORS 就绪的 OpenClaw Mac
约 $16.9/天起