缓存失效本质是url编码不一致导致key错位:浏览器请求含%e4%b8%ad%e6%96%87,而服务端生成key时用urldecode()转为“中文”或未统一标准化,使同一页面被存为不同key,查不到缓存。

缓存失效时 URL 带中文编码不匹配,本质是缓存 key 的生成逻辑与实际请求的 URL 解码结果不一致,导致“同一个页面”被当成多个不同 key 存储或查询,最终查不到缓存。这不是 Redis 或 Memcached 本身的问题,而是应用层对中文 URL 处理不统一造成的隐性失效。
确认是否为 URL 编码不一致导致的缓存未命中
先抓一个典型失效请求的完整 URL(比如 /article/标题-测试-中文),在服务端日志或调试中打印出两处关键值:
- 用户浏览器发出的实际请求路径(原始字符串,含 %E4%B8%AD%E6%96%87 这类编码)
- 你代码中用于生成缓存 key 的 URL 字符串(是直接取
$_SERVER['REQUEST_URI']?还是经过urldecode()或rawurldecode()处理?)
如果二者不一致(例如一个保留了 %E4%B8%AD,另一个已转成“中”),那 key 就天然错位,缓存必然无法复用。
检查 key 构建环节的编码处理逻辑
常见错误模式包括:
- 前端发请求用
encodeURI,后端用urldecode解,但某些框架自动做了二次解码,导致多解一次 - 使用 Nginx 或 CDN 对 URL 做了标准化重写(如自动解码、去除重复斜杠、小写化),而缓存 key 没同步该规则
- PHP 中
$_GET数组的值默认已解码,但$_SERVER['QUERY_STRING']是原始编码串,混用会导致 key 不一致 - Redis key 中直接拼接未规范化的中文路径,而 Redis 协议本身不关心编码,但不同客户端对二进制 key 的序列化表现可能有差异
统一 URL 标准化后再生成缓存 key
建议在生成缓存 key 前,强制走一遍标准化流程:
- 对路径部分(path)使用
rawurldecode()→mb_convert_encoding(..., 'UTF-8', 'UTF-8')确保内部统一为 UTF-8 字符串 - 对查询参数(query)建议不参与 key 构建,或先按字母序排序键名再拼接,避免
a=1&b=2和b=2&a=1被视为两个 key - 最终 key 可哈希化:用
md5($normalized_path . $sorted_query_string)代替原始 URL,彻底规避编码/空格/大小写等干扰
验证方式:手动模拟 key 查询
在 redis-cli 中执行:
exists "cache:article:"$(echo -n "/article/%E4%B8%AD%E6%96%87" | md5sum | cut -d' ' -f1) exists "cache:article:"$(echo -n "/article/中文" | md5sum | cut -d' ' -f1)
如果只有一条返回 1,说明 key 构建确实存在编码分歧;两条都返回 0,则问题可能出在写入阶段——需检查缓存写入时是否用了同样逻辑。











