使用Cloudflare worker加速Cloudflare R2访问速度

cloudflare R2 提供了免费10G的对象存储并且兼容Amazon S3 api 操作, 与大多数对象存储提供商不一样的是R2的流出流量是免费的, 不用担心请求被恶意刷爆第二天银行来收房子的情况发生. 但是cloudflare给R2分配的ip都是xxx.xxx.xxx.1形式的ip, 这种ip节点在国内的访问体验很不好, 特别是在移动网络下, 基本无法访问. img

然而计算机领域里有句叫’没有什么问题是加一个中间层不能解决的’, 而cloudflare里的worker刚好可以当这个’中间层’. worker是cloudflare提供的一个可以运行js/ts代码的serverless容器.

设计原理

我们无法更改cloudflare为R2分配的ip, 但是worker的路由我们是可以配置. 由此我们可以通过优选好的路由连接到worker, 然后让worker作为中间人去帮我们访问R2的资源, worker和r2同属于cloudflare网络, 它们之间的通信会非常快. 这样一来就能实现R2的’加速’访问. img

本篇文章演示中R2绑定的访问域名是static.merack.top, worker通过worker路由绑定的域名是cdn.merack.top. 其中cdn.merack.top是最终给用户看到的域名. 用户向cdn.merack.top发出请求调用worker, worker请求R2: static.merack.top, 将R2的数据返回给用户.

创建worker

点击左侧workers和pages, 新建一个hello world 的worker, 不用选其他模板. img

然后点击右上角的编辑代码按钮修改为如下代码

const R2_DOMAIN = 'static.merack.top'; // 改成自己的R2公共访问域名

async function handleRequest(request) {
  try {
    const url = new URL(request.url);
    
    // 构建新的R2资源URL
    const targetUrl = new URL(`https://${R2_DOMAIN}`);
    targetUrl.pathname = url.pathname;
    targetUrl.search = url.search;

    // 复制并修改请求头
    const headers = new Headers(request.headers);
    headers.set('Host', R2_DOMAIN);
    headers.delete('Cookie'); // 移除不必要的cookie头

    // 创建新请求
    const newRequest = new Request(targetUrl, {
      method: request.method,
      headers: headers,
      redirect: 'follow'
    });

    let response = await fetch(newRequest);
    return response;
  } catch (err) {
    // 错误处理
    return new Response(err.stack, { 
      status: 500,
      headers: { 'Content-Type': 'text/plain' }
    });
  }
}

// 监听所有请求
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
});

R2_DOMAIN 常量改成自己的R2公共访问域名, 比如我这里是static.merack.top, 然后点击部署

配置worker路由

点击设置->域和路由, 点击右上方的添加按钮, 类型选择路由 img

接下来填入需要面向用户的那个域名, 路径填/*, 例如我这里填的就是cdn.merack.top/* img

这样用户访问cdn.merack.top时就触发worker去代理请求到R2, 但是此时还并不是优选的路由, 我们还需要修改下DNS解析 添加DNS记录让cdn.merack.top指向优选好的cloudflare cdn节点ip, 关于cf如何优选ip网上有很多教程就不赘述了, 图方便的话可以直接添加一个cname记录到别人的优选域名, 这里我用的是 cloudflare.182682.xyz , 也可以填我的博客域名www.merack.top , 但是注意后面的小黄云记得关闭, 让其状态为 ‘仅DNS’ 模式, 这样你的cname才有意义.img点击保存后就可以将我们的访问域名换成worker路由的域名看看效果了.

测试

经过一番折腾后效果对比以前有了很大提升, 但还是有些地区无法正常访问, 这取决于当地的网络状况和优选ip的质量. 如果要做到100%的可用性的话, 建议还是花点钱买个好点的服务, 比如Amazon S3 + Amazon Cloudfont, 如果你的域名有备案, 国内云服务商提供的对象存储也是不错的选择. img

限制

这个方案的限制主要来自worker. worker的免费订阅最关键的两个限制是CPU时间和日请求额度. img

  1. 每个请求的CPU时间是10毫秒, 超过这个时间请求会中断, 因此该方案不适用于大文件下载, 下到一半会中断. 10ms的时间最多能下到多大的文件没有测试过, 我用来请求存储本博客图片资源的R2的中值CPU时间不到1ms, 如果只是用作图片类型的文件加速, 10ms绰绰有余.
  2. worker的每日请求是十万, 因此该方案只能适用于日访问量在万级以下的小博客. 如果你的日访问量都到万级以上了, 应该不缺那点小钱去买个好点存储和cdn了吧. 为了防止脚本恶意刷请求, 可以配合cloudflare waf里的速率限制规格做一定的限制, 关于cloudflare waf我之前有写过文章介绍.img

扩展

1.本文例子中的使用场景是主要图片访问加速, 那么就会涉及到缓存时间的问题. worker返回的静态资源响应是会带有缓存控制的响应头(Cache-Control)的 img

如果你想修改缓存的过期时间, 可以使用worker的cache api来控制, 具体可以参照官方文档: https://developers.cloudflare.com/workers/runtime-apis/cache/ https://developers.cloudflare.com/workers/reference/how-the-cache-works/ 2.虽说本文是以加速r2的访问为主题, 当也可用于加速其他的网站, 只要把代码中的 R2_DOMAIN 常量改改就可以做到. 但如果你代理的是某些版权意识比较看重的大公司的站点, 访问量大了他们可能会向cloudflare投诉, 认为你在进行’假冒官网’, ‘欺骗用户’等欺诈行为, 那么cloudflare可能会封禁你的账号.

验证与自查

  1. curl -I https://cdn.merack.top/<图片路径> 返回 200,内容与直连 static.merack.top 一致
  2. 对比直连与经 worker 访问同一图片的耗时,worker 路径明显更快
  3. 大文件下载测试:超过 10ms CPU 时间上限会中断,确认只用于图片等小文件
  4. 观察 worker 面板的请求数与 CPU 时间,确认未逼近免费额度(日 10 万请求、10ms CPU/请求)

参考