一个 cloudflare 的worker代理

一个 cloudflare 的worker代理,可以自定义代理方式,通过 xxx.com/sub 的方式,通过sub目录区分代理目标

proxy.js
const WHITELIST_MAP = {
  'nvidia.github.io': 'https://nvidia.github.io'
};
 
export default {
  async fetch(request, env, ctx) {
    // 可选:记录请求日志
    console.info({ message: 'Received request', url: request.url });
 
    const url = new URL(request.url);
    const pathname = url.pathname;
 
    // 提取 subDomain:从第一个 / 后的内容到下一个 / 或末尾
    const firstSlash = pathname.indexOf('/', 1); // 跳过开头的 /
    const subDomain = firstSlash === -1 ? pathname.slice(1) : pathname.slice(1, firstSlash);
    const otherPath = firstSlash === -1 ? '' : pathname.slice(firstSlash + 1);
 
    // 检查 subDomain 是否在白名单中
    if (!subDomain || !WHITELIST_MAP.hasOwnProperty(subDomain)) {
      return new Response('Not Found (Invalid subDomain)', {
        status: 404,
        headers: { 'Content-Type': 'text/plain' }
      });
    }
 
    // 构造目标 URL
    const targetBaseUrl = WHITELIST_MAP[subDomain];
    const targetUrl = new URL(`${targetBaseUrl}/${otherPath}`);
    targetUrl.search = url.search; // 保留查询参数
 
    // 创建代理请求
    const proxyRequest = new Request(targetUrl, request);
    proxyRequest.headers.set('Host', targetUrl.hostname);
 
    try {
      const response = await fetch(proxyRequest);
 
      // 修复:正确处理不可变响应头
      const corsHeaders = new Headers(response.headers);
      corsHeaders.set('Access-Control-Allow-Origin', '*');
      corsHeaders.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
      corsHeaders.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
 
      // 克隆响应体(必须,因为 Response 不可变)
      const modifiedResponse = new Response(response.body, {
        status: response.status,
        statusText: response.statusText,
        headers: corsHeaders
      });
 
      return modifiedResponse;
    } catch (error) {
      console.error('Proxy Error:', error.message);
      return new Response(`Proxy Error: ${error.message}`, { 
        status: 502,
        headers: { 
          'Content-Type': 'text/plain',
          'Access-Control-Allow-Origin': '*'
        }
      });
    }
  }
};