方案四:利用Cloudflare Workers等边缘计算实现访问
从一次失败的curl请求说起
上周三深夜,我正在调试一个自动化下载脚本,突然发现所有对ZLibrary的请求都返回403。熟悉的IP封锁又来了------这次不是简单的地区限制,而是针对自动化流量的深度检测。常规的代理轮换已经失效,TCP连接在建立后几秒内就被切断。这种时候,边缘计算平台就成了破局的关键。
边缘计算的核心优势
Cloudflare Workers这类服务有个天然优势:它们运行在Cloudflare的全球边缘节点上,IP地址池既庞大又"干净"。更重要的是,这些IP通常属于云服务商的白名单范畴,很多针对个人IP的封锁策略在这里会失效。我们不是要"隐藏"请求,而是要把请求"变成"来自受信任基础设施的合法流量。
Worker脚本的实战设计
下面这个脚本是我调试了三个版本的最终产物,注意看注释里的细节:
javascript
// 注意:必须设置环境变量TARGET_HOST,别硬编码
// 我在测试阶段因为硬栽过坑------域名变更时改起来太麻烦
export default {
async fetch(request, env) {
// 只处理GET请求,避免不必要的风险
if (request.method !== 'GET') {
return new Response('Method not allowed', { status: 405 });
}
const targetHost = env.TARGET_HOST || 'zlibrary-global.se';
// 关键:保留原始请求路径和查询参数
const url = new URL(request.url);
const targetUrl = `https://${targetHost}${url.pathname}${url.search}`;
// 构造看起来像浏览器的请求头
// 这里有个细节:User-Agent不能随便编,要用常见的浏览器字符串
const modifiedHeaders = new Headers(request.headers);
modifiedHeaders.set('Host', targetHost);
modifiedHeaders.set('User-Agent',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
modifiedHeaders.set('Accept',
'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8');
modifiedHeaders.set('Accept-Language', 'en-US,en;q=0.5');
// Referer要设置成目标站点的搜索页,别留空
if (!modifiedHeaders.has('Referer')) {
modifiedHeaders.set('Referer', `https://${targetHost}/`);
}
// 超时设置很重要,边缘函数有执行时间限制
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);
try {
const response = await fetch(targetUrl, {
headers: modifiedHeaders,
redirect: 'manual', // 手动处理重定向,避免循环
signal: controller.signal
});
clearTimeout(timeoutId);
// 处理重定向------直接返回重定向响应
if ([301, 302, 307, 308].includes(response.status)) {
const location = response.headers.get('Location');
if (location) {
return Response.redirect(location, response.status);
}
}
// 返回修改后的响应
// 注意:这里要删除一些敏感头部,比如CF-Ray
const responseHeaders = new Headers(response.headers);
responseHeaders.delete('CF-Ray');
responseHeaders.delete('CF-Cache-Status');
return new Response(response.body, {
status: response.status,
headers: responseHeaders
});
} catch (error) {
clearTimeout(timeoutId);
// 错误处理要友好,别暴露内部信息
if (error.name === 'AbortError') {
return new Response('Request timeout', { status: 504 });
}
return new Response('Service temporarily unavailable', { status: 503 });
}
}
};
部署时的注意事项
部署这个Worker时,有几个容易忽略的点:
第一,路由配置别用通配符*,要精确到你的子域名,比如zl-proxy.your-domain.com/*。通配符容易引来不必要的扫描和滥用。
第二,环境变量管理要用Wrangler的加密存储,别在代码里写死。我见过有人把配置提交到公开仓库,第二天账号就异常了。
第三,免费计划有每日10万请求的限制,如果个人使用完全足够,但如果是团队共享,记得监控用量。超过限制后CF会优雅降级,不会直接断流。
请求频率的控制策略
即使用了Workers,也不能无节制地请求。我的经验是:
- 添加随机延迟,模拟人工操作间隔
- 实现简单的令牌桶算法控制并发
- 遇到429状态码时自动退避,指数级增加等待时间
javascript
// 简单的退避实现示例
let retryDelay = 1000;
const maxDelay = 60000;
while (retryCount < 3) {
const response = await fetch(request);
if (response.status !== 429) break;
await new Promise(resolve => setTimeout(resolve, retryDelay));
retryDelay = Math.min(retryDelay * 2, maxDelay);
retryCount++;
}
关于其他边缘平台的思考
除了Cloudflare Workers,Vercel Edge Functions、Netlify Functions也能实现类似效果。但选择时要考虑几点:冷启动时间、网络质量、价格模型。CF Workers的免费额度最慷慨,全球节点覆盖也最好,适合这种代理场景。Vercel在亚洲节点优化更好,但免费额度较少。
个人经验与建议
这种方案我用了大半年,稳定性比自建VPS高得多。但有几个心得:
第一,别把Worker当成万能钥匙。它解决的是IP封锁问题,不解决内容合规问题。技术方案要建立在合法合规的前提下。
第二,定期更新User-Agent字符串。虽然不像客户端指纹那么严格,但太旧的UA还是会触发一些基础检测。
第三,考虑结合方案三(浏览器自动化)使用。Worker负责获取页面,本地脚本解析内容------这样既利用了边缘网络的稳定性,又保持了本地处理的灵活性。
最后提醒一点:所有技术方案都有生命周期。边缘计算今天有效,不代表明天还能用。保持对网络协议的理解,比掌握某个具体工具更重要。当这个方案失效时,你能否基于对HTTP协议、TLS握手、CDN原理的理解,快速设计出下一个方案?这才是工程师的价值所在。
(下一篇我们聊聊方案五:基于Tor网络的分布式访问策略,那个方案更适合需要高度匿名的场景。)