You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cloudflare Worker Cache用作快速KV存储的实现问题排查

Cloudflare Worker Cache 作为前置缓存层无法正常工作的问题排查与修复

我尝试将Cloudflare Worker Cache作为数据库的前置缓存层,但控制台持续触发“Failed to set cache value”错误,调用getCacheValue也无法返回内容。以下是我的实现代码:

const CACHE_URL_PREFIX = 'https://api.example.com/';

function getCache() {
  return caches.default;
}

function generateHash(str: string) {
  let hash = 0, i, chr;
  for (i = 0; i < str.length; i++) {
    chr = str.charCodeAt(i);
    hash = ((hash << 5) - hash) + chr;
    hash |= 0;
  }
  return hash.toString(36);
}

function toUniqueUrlPath(str: string) {
  let normalizedStr = str.trim();

  normalizedStr = normalizedStr.toLowerCase();
  
  normalizedStr = normalizedStr.replace(/[^a-z0-9 -]/g, '-');
  normalizedStr = normalizedStr.replace(/\s+/g, '-'); 

  const uniqueHash = generateHash(str);

  return `${normalizedStr}-${uniqueHash}`;
}

export function getCacheKey(key: string) {
  const normalizedKey = toUniqueUrlPath(key);

  const url = (CACHE_URL_PREFIX + normalizedKey)
    .replace(/\/+\/g, '/');

  return new Request(url);
}

export async function getCacheValue<T>(key: string) {
  const cache = await getCache();
  const cacheKey = getCacheKey(key);
  
  const cachedResponse = await cache.match(cacheKey);
  
  if (cachedResponse) {
    return await cachedResponse.json() as T;
  }

  return undefined;
}


export async function setCacheValue<T>(key: string, value: T, ttl: number) {
  const cache = await getCache();
  const cacheKey = getCacheKey(key);

  const response = new Response(JSON.stringify(value), {
    headers: {
      'Content-Type': 'application/json',
      'Cache-Control': `public, max-age=${ttl}`
    }
  });

  await cache.put(cacheKey, response);

  const valueFromCache = await getCacheValue<T>(key); 

  if (!valueFromCache) {
    console.error('Failed to set cache value', {
      key,
      value,
      ttl,
      url: cacheKey.url,
    });
  }
}

问题分析与修复方案

1. 正则表达式语法错误

getCacheKey中的replace(/\/+\/g, '/')存在语法错误,正则表达式里的斜杠未正确转义,导致无法合并连续的URL斜杠。修正为:

const url = (CACHE_URL_PREFIX + normalizedKey).replace(/\/+/g, '/');

2. Cache 匹配规则不兼容

cache.match默认会严格匹配请求的方法、Headers等信息,而创建Request对象时隐式的默认值(比如Accept头)可能导致存入和查询的缓存键不匹配。需要在match时添加匹配选项,或统一Request的创建参数:

// 在getCacheValue中修改match调用
const cachedResponse = await cache.match(cacheKey, {
  ignoreMethod: true,
  ignoreVary: true
});

// 或在getCacheKey中明确指定Request参数,确保一致性
return new Request(url, {
  method: 'GET',
  headers: new Headers({ 'Content-Type': 'application/json' })
});

3. Hash 生成逻辑冗余

toUniqueUrlPath中用原始字符串生成Hash,但前面已经做了归一化处理,改用归一化后的字符串生成Hash可以避免不必要的计算差异:

const uniqueHash = generateHash(normalizedStr);

修正后的完整代码

const CACHE_URL_PREFIX = 'https://api.example.com/';

function getCache() {
  return caches.default;
}

function generateHash(str: string) {
  let hash = 0, i, chr;
  for (i = 0; i < str.length; i++) {
    chr = str.charCodeAt(i);
    hash = ((hash << 5) - hash) + chr;
    hash |= 0;
  }
  return hash.toString(36);
}

function toUniqueUrlPath(str: string) {
  let normalizedStr = str.trim().toLowerCase();
  
  normalizedStr = normalizedStr.replace(/[^a-z0-9 -]/g, '-');
  normalizedStr = normalizedStr.replace(/\s+/g, '-'); 

  const uniqueHash = generateHash(normalizedStr);

  return `${normalizedStr}-${uniqueHash}`;
}

export function getCacheKey(key: string) {
  const normalizedKey = toUniqueUrlPath(key);
  const url = (CACHE_URL_PREFIX + normalizedKey).replace(/\/+/g, '/');

  return new Request(url, {
    method: 'GET',
    headers: new Headers({ 'Content-Type': 'application/json' })
  });
}

export async function getCacheValue<T>(key: string) {
  const cache = await getCache();
  const cacheKey = getCacheKey(key);
  
  const cachedResponse = await cache.match(cacheKey, {
    ignoreMethod: true,
    ignoreVary: true
  });
  
  if (cachedResponse) {
    return await cachedResponse.json() as T;
  }

  return undefined;
}


export async function setCacheValue<T>(key: string, value: T, ttl: number) {
  const cache = await getCache();
  const cacheKey = getCacheKey(key);

  const response = new Response(JSON.stringify(value), {
    headers: {
      'Content-Type': 'application/json',
      'Cache-Control': `public, max-age=${ttl}`
    }
  });

  await cache.put(cacheKey, response);

  const valueFromCache = await getCacheValue<T>(key); 

  if (!valueFromCache) {
    console.error('Failed to set cache value', {
      key,
      value,
      ttl,
      url: cacheKey.url,
    });
  }
}

额外注意事项

  • Cloudflare Worker Cache的键长度限制为2048字符,需确保生成的URL不超过该限制
  • 可移除setCacheValue中立即调用getCacheValue的校验逻辑,减少冗余缓存查询
  • 若缓存内容频繁更新,需合理设置max-age避免无效缓存

内容的提问来源于stack exchange,提问作者Marcus 123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:57:34