记一次CloudflareWorkers图片缓存失败解决


缓存失败

我前天做了个项目,使用 CloudflareWorkers 来处理地球图像请求,访客访问Workers地址Workers返回最新图片,我当时想用 Cloudflare 的缓存来避免过多不必要重复的Workers请求刷爆我的账单,于是我我在 Worker 中设置最新图片的缓存头

return new Response(imageResponse.body, {
    headers: {
        'Content-Type': 'image/png',
        'Cache-Control': 'public, max-age=300, s-maxage=600'
    }
});

但是,事情没有这么简单,我实际打开发现Cloudflare并没有缓存我的图片,并且我每一次刷新都结结实实的发送给了Workers处理,我在F12中发现响应头缺失cf-cache-status字段:

修改

我尝试过设置Cloudflare Cache Rules、将访问改成访问earth.png,但Cloudflare就是不缓存图片,就是没有cf-cache-status字段,就是不缓存,我无奈的只能搜索、发帖求助、骚扰AI,但都无功而返,直到GPT说漏了嘴,提到了 Cache API

我搜了下,这似乎是Cloudflare官方提供的缓存API 官方文档 我研究了下把文档复制给了GPT,但GPT输出的代码全特么是报错,扯皮了半小时,没办法,只能人工亲自修改:

 export default {
    async fetch(request) {
        const url = new URL(request.url);
        const cache = caches.default; 
        
        ......
        
const cacheKey = new Request(imageUrl); // 使用图像 URL 作为缓存键
let response = await cache.match(cacheKey); // 尝试从缓存中获取图像
        
        ......
        
if (!response) {
            const imageResponse = await fetch(imageUrl); // 获取图像
            if (!imageResponse.ok) {
                throw new Error(`Failed to fetch image: ${imageResponse.status}`);
            }

            // 创建新的响应并缓存
            response = new Response(imageResponse.body, {
                headers: {
                    'Content-Type': 'image/png',
                    'Cache-Control': 'public, s-maxage=600', // Cloudflare缓存10分钟
                    'Access-Control-Allow-Origin': '*', // 允许任何位置请求
                }
            });

            // 将响应存入缓存
            await cache.put(cacheKey, response.clone());
        ......

一番修正后,F12查看终于是命中了缓存

总结

Cloudflare好像是更新了Workers更新规则,现在不再主动缓存Workers,现在需要在Workers里手动使用Cache API缓存你想要缓存的内容,关键点如下:

  • 缓存键(Cache Key)必须使用有效的 URL 格式,缓存键就像你存放缓存的货架编号,需要使用有效URL
  • 缓存键可以瞎设置,但必须符合URL格式规则
  • URL不需要实际存在、可用,URL就像你的缓存Key,这个Key的格式只需要包含“**https://**”,后面的字符可以随便填
  • 只要你的Workers是在同一个数据中心的,那么这个缓存可以共用

这是我阅读文档后写了一段Workers代码示例:

export default {
  async fetch(request, env, ctx) {
    const cache = caches.default;
    const cacheKey = new URL(request.url); // 创建缓存键
    // 尝试从缓存中获取响应
    let response = await cache.match(cacheKey);
    if (!response) {
      // 没缓存,则创建新的响应
      response = new Response('Fuck World!', {
        headers: { 'Cache-Control': 'max-age=3600' } // 使用传入的头部
      });
      // 将响应存入缓存
      await cache.put(cacheKey, response.clone());
    }
    return response; // 返回响应
  },
};

经我观察,GPT的回答似乎完全是凭空捏造的,我怀疑是AI的知识库中缺乏相关信息、标注,不过如果把示例代码、文档打包发给他回好很多

下面是我折腾好的地球实时图像,10分钟更新一次



  目录