如何在 Cloudflare Workers 中调用第三方 API 遇到 CORS 怎么解决

文章导读
最推荐的做法是在 Worker 代码中直接给返回给浏览器的响应添加 CORS 响应头,而不是试图修改第三方 API 的设置,因为 Worker 作为服务端中间层不受浏览器 CORS 策略限制。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
A A

最推荐的做法是在 Worker 代码中直接给返回给浏览器的响应添加 CORS 响应头,而不是试图修改第三方 API 的设置,因为 Worker 作为服务端中间层不受浏览器 CORS 策略限制。

先说结论:Cloudflare Workers 发起的后端请求不会触发 CORS 报错,报错通常是因为浏览器访问 Worker 时缺少响应头,需在 Worker 返回的 Response 中手动设置 Access-Control 相关 header。

  • 先确认:检查浏览器控制台报错是发生在浏览器请求 Worker 阶段,还是 Worker 请求第三方 API 阶段。
  • 先处理:在 Worker 代码中构建 Response 对象时,写入 Access-Control-Allow-Origin 等头部信息。若涉及凭证,严禁使用通配符 *。
  • 再验证:发送 OPTIONS 预检请求,确认 Worker 是否正确放行跨域方法。

命令速用版

如果你希望快速修复,可以在 Worker 脚本中使用现代模块语法,统一给响应添加 CORS 头。以下是一个最小可用的代码片段,包含错误处理和动态 Origin 匹配:

export default {
  async fetch(request, env, ctx) {
    // 获取请求源,用于动态匹配 CORS
    const origin = request.headers.get('Origin') || '*';
    
    // 处理预检请求
    if (request.method === 'OPTIONS') {
      return new Response(null, {
        headers: {
          'Access-Control-Allow-Origin': origin,
          'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
          'Access-Control-Allow-Headers': 'Content-Type, Authorization',
          'Access-Control-Max-Age': '86400',
        },
      })
    }

    try {
      // 调用第三方 API
      const response = await fetch('https://api.example.com/data')
      
      // 创建新 Headers 对象,避免继承不必要的敏感头
      const newHeaders = new Headers(response.headers);
      newHeaders.set('Access-Control-Allow-Origin', origin);
      newHeaders.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
      
      // 若前端需要凭证,需显式允许且 Origin 不能为 *
      // newHeaders.set('Access-Control-Allow-Credentials', 'true'); 
      
      return new Response(response.body, {
        status: response.status,
        headers: newHeaders
      });
    } catch (err) {
      // 捕获第三方 API 超时或失败,防止 Worker 抛出未捕获异常
      return new Response('External API Error', { status: 502 });
    }
  }
}

注意:若前端请求携带凭证,Access-Control-Allow-Origin 严禁使用 *,必须动态匹配请求头中的 Origin。

为什么会这样

CORS(跨域资源共享)是浏览器的安全机制,只限制运行在浏览器环境下的 JavaScript 代码。当你的前端页面直接请求第三方 API 时,浏览器会检查响应头,如果没有允许的标识就会拦截。

Cloudflare Workers 运行在边缘服务器上,属于服务端环境。Worker 向第三方 API 发起 fetch 请求时,不受浏览器 CORS 策略约束,可以直接获取数据。问题通常出在第二步:当 Worker 把数据返回给浏览器时,浏览器认为这是跨域请求(前端域名与 Worker 域名不同),因此要求 Worker 的响应中必须包含 CORS 允许头。

分步处理

第一步:定位报错来源
打开浏览器开发者工具的 Network 面板,找到红色的请求。如果报错是 Access-Control-Allow-Origin 且请求 URL 是你的 Worker 域名,说明需要在 Worker 代码中加头。如果请求 URL 是第三方 API 域名且由前端直接发起,说明你需要把请求改为先发给 Worker。

如何在 Cloudflare Workers 中调用第三方 API 遇到 CORS 怎么解决

第二步:修改 Worker 代码
采用现代 export default 语法重构 Worker。在返回 Response 对象前,使用 headers.set 添加头部。如果需要支持凭证(cookies),Access-Control-Allow-Origin 不能为 *,必须指定具体域名,且需添加 Access-Control-Allow-Credentials: true

第三步:处理预检请求
某些请求(如携带自定义头或使用 PUT/DELETE 方法)会先发送 OPTIONS 请求。确保你的代码能识别 request.method === 'OPTIONS' 并直接返回 200 状态码及相应的 Allow 头,不要将 OPTIONS 请求转发给第三方 API。

第四步:增加异常捕获
在调用第三方 API 的 fetch 外部包裹 try-catch 块。防止第三方 API 超时或返回 5xx 错误导致 Worker 进程崩溃或返回不友好的默认错误页。

怎么验证是否生效

浏览器控制台检查
刷新页面,观察 Network 面板中原本报错的请求是否状态码变为 200 且没有 CORS 红色报错。点击请求详情,查看 Response Headers 中是否包含 Access-Control-Allow-Origin

命令行验证
使用 curl 模拟预检请求,检查头部返回情况:

如何在 Cloudflare Workers 中调用第三方 API 遇到 CORS 怎么解决
curl -v -X OPTIONS -H "Origin: https://your-frontend.com" https://your-worker.workers.dev

确认返回头中包含 Access-Control-Allow-MethodsAccess-Control-Allow-Origin

常见坑

1. 通配符与凭证冲突
如果前端请求设置了 credentials: 'include',Worker 响应头中的 Access-Control-Allow-Origin 不能是 *,必须与请求头中的 Origin 一致,否则浏览器会直接拦截请求。

2. 缓存导致的预检失败
浏览器会缓存 OPTIONS 预检结果。如果修改了 Worker 代码但浏览器仍报错,尝试硬刷新或清除缓存。可以在 Worker 响应中添加 Access-Control-Max-Age 控制缓存时间。

3. 第三方 API 的 CORS 限制
虽然 Worker 请求第三方 API 不受浏览器 CORS 限制,但部分 API 服务端会校验 Referer 或 Origin。如果遇到 403 Forbidden,可能需要在 Worker 请求第三方时伪造或移除相关头部,而不是解决 CORS 问题。

4. 响应头修改无效
如果直接返回 fetch 的结果,某些只读头部可能无法修改。建议使用 new Headers(response.headers) 克隆后修改,再构建新的 Response 对象。

5. 未处理外部异常
若第三方 API 超时,Worker 默认可能抛出异常导致请求中断。务必使用 try-catch 捕获外部 fetch 错误,并返回合理的 HTTP 状态码(如 502)。