将CORS检查应用迁移至Cloudflare Workers时的Header缺失问题咨询
我正尝试将CORS检查应用从Heroku迁移至Cloudflare Workers,该应用原本使用axios向目标网站发送OPTIONS请求,检测是否存在x-frame-options Header,并根据其值返回布尔结果。迁移后功能无法正常运行,我是否可以认为Cloudflare会剥离这些Header,导致该功能无法在Cloudflare Workers上实现?
// node_modules/itty-router/dist/itty-router.mjs var e = ({ base: e2 = "", routes: r = [] } = {}) => ({ __proto__: new Proxy({}, { get: (a, o, t) => (a2, ...p) => r.push([o.toUpperCase(), RegExp(`^${(e2 + a2).replace(/(\/?)\*/g, "($1.*)?").replace(/(\/$)|((?<=\/)\/)/, "").replace(/:(\w+)\+/, "(?<$2>.*)").replace(/:(\w+)(\?)?(\.)?/g, "$2(?<$1>[^/]+)$2$3").replace(/\.(?=[\w(])/, "\\.").replace(/\)\.\?\(([^\[]+)\[\^/g, "?)\\.?($1(?<=\\.)[^\\.")}/*$`), p]) && t }), routes: r, async handle(e3, ...a) { let o, t, p = new URL(e3.url), l = e3.query = {}; for (let [e4, r2] of p.searchParams) l[e4] = void 0 === l[e4] ? r2 : [l[e4], r2].flat(); for (let [l2, s, c] of r) if ((l2 === e3.method || "ALL" === l2) && (t = p.pathname.match(s))) { e3.params = t.groups || {}; for (let r2 of c) if (void 0 !== (o = await r2(e3.proxy || e3, ...a))) return o; } } }); // src/index.ts var router = e(); var corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS", "Access-Control-Max-Age": "86400" }; function jsonResponse(body) { return new Response(JSON.stringify(body), { status: 200, headers: { "Content-Type": "application/json", "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload" } }); } function handleOptions(request) { let headers = request.headers; if (headers.get("Origin") !== null && headers.get("Access-Control-Request-Method") !== null && headers.get("Access-Control-Request-Headers") !== null) { let respHeaders = { ...corsHeaders, "Access-Control-Allow-Headers": request.headers.get("Access-Control-Request-Headers") }; return new Response(null, { headers: respHeaders }); } else { return new Response(null, { headers: { Allow: "GET, HEAD, POST, OPTIONS" } }); } } router.options("/test-cors", async function(request) { return handleOptions(request); }); router.post("/test-cors", async function(request) { const url = request.body.url; const externalRequest = new Request(url, { method: "head" }); try { let response = await fetch(externalRequest); if (response.headers.get("x-frame-options") !== null) { const frameOptionsValue = response.headers.get("x-frame-options"); if (frameOptionsValue === "SAMEORIGIN") { return jsonResponse({ canAccess: false }); } else { return jsonResponse({ canAccess: true }); } } else { return jsonResponse({ canAccess: true }); } } catch (error) { console.error(error); if (error.code === "ENOTFOUND" || error.response.status === 404) { return jsonResponse({ canAccess: false, reason: "NOT_FOUND" }); } else { return jsonResponse({ canAccess: false }); } } }); router.all("*", (request, args) => { return new Response("Not Found", { status: 404, headers: { "Content-Type": "text/html; charset=utf-8", "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload" } }); }); var src_default = { async fetch(request, env, ctx) { return router.handle(request); } }; export { src_default as default }; //# sourceMappingURL=index.js.map
Cloudflare Workers 不会主动剥离x-frame-options这类响应头,问题出在你的代码逻辑上:
请求方法不匹配:原Heroku应用使用
OPTIONS请求检测,但迁移后的Worker代码里发送的是HEAD请求。部分网站对不同请求方法返回的响应头可能不一致,比如有些网站仅在GET/HEAD请求返回x-frame-options,但也有部分网站只会针对浏览器发起的请求返回该头,或者对非浏览器请求(比如Worker的fetch)隐藏。请求体解析问题:你直接从
request.body.url获取目标URL,但在Cloudflare Workers中,request.body是一个ReadableStream,不能直接读取属性,需要先解析请求体:// 修正后的POST处理逻辑 router.post("/test-cors", async function(request) { const body = await request.json(); // 先解析JSON请求体 const url = body.url; // ... 后续逻辑 });错误处理逻辑问题:
error.response在Worker的fetch抛出的错误中不存在,因为fetch仅在网络层面失败时抛出错误(比如DNS解析失败),HTTP错误(如404)不会抛出,而是返回ok: false的Response对象。需要调整错误处理:try { let response = await fetch(externalRequest); if (!response.ok) { // 处理HTTP错误,比如404 return jsonResponse({ canAccess: false, reason: "HTTP_ERROR", status: response.status }); } // ... 检测x-frame-options的逻辑 } catch (error) { console.error(error); // 仅处理网络错误 return jsonResponse({ canAccess: false, reason: "NETWORK_ERROR" }); }请求头模拟:部分网站会根据请求的
User-Agent等头判断是否返回x-frame-options,可以模拟浏览器请求头提高准确性:const externalRequest = new Request(url, { method: "HEAD", headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" } });
总结:Cloudflare Workers本身不会影响你获取响应头,核心问题是代码中的请求方法、请求体解析、错误处理逻辑与原应用不一致,以及部分网站对请求来源的判断导致响应头缺失。调整上述几点后功能应该可以正常运行。
内容的提问来源于stack exchange,提问作者Bartlomiej Lewandowski

