一个 cloudflare 的worker代理,可以自定义代理方式,通过 xxx.com/sub 的方式,通过sub目录区分代理目标
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': '*'
}
});
}
}
};