缓存键不能直接使用屏幕分辨率,而应通过设备类型+视口断点(如mobile/tablet/desktop)及归一化dpr(1/2/3)等可信信号构建;禁止用window.screen.width、url参数或服务端dom属性生成key。

缓存键里不能直接塞屏幕分辨率,因为分辨率是客户端 JavaScript 运行时才能获取的值,服务端预渲染或网关层根本拿不到。真要按分辨率做差异化缓存,得靠间接、可信、可验证的代理信号。
用设备类型 + 视口断点代替具体像素值
真实项目中,没人用1920x1080这种精确值当缓存 key——它既不可靠(浏览器窗口可拖拽、缩放、分屏),又易被伪造,还导致缓存爆炸。正确做法是映射到语义化断点:
- 服务端从
User-Agent和Sec-CH-UA-Mobile等请求头判断设备大类(mobile / tablet / desktop) - 结合已知的主流视口宽度范围(如 mobile: ≤768px,tablet: 769–1024px,desktop: ≥1025px),在 CDN 或网关层打上
viewport:mobile这类 tag - 缓存键写成
prerender:zh:mobile:/list?cat=shoes,而非prerender:1920x1080:/list?cat=shoes
让客户端参与 key 构建(需服务端校验)
某些场景必须区分高清屏(Retina)和普通屏,这时可让前端在首次请求时上报一个可信的设备像素比(window.devicePixelRatio),但不能直接拼进 key,而是由服务端做归一化处理:
- 前端通过
X-DPR请求头传值(如X-DPR: 2) - 服务端只接受
1、2、3三个合法值,其他一律降级为1 - 最终 key 中体现为
dpr2这样的固定标识,例如:prerender:en:mobile:dpr2:/product?id=123
禁用动态分辨率作为 key 维度的典型错误
以下操作会引发严重问题,务必避免:
- 读取
window.screen.width后发 Ajax 请求再生成缓存——此时 HTML 已输出,快照早已生成完毕 - 把 URL 中带
?w=375&h=812这类参数当作分辨率依据——参数可被任意篡改,缓存污染风险极高 - 在 SSR 模板里调用
document.documentElement.clientWidth——服务端没有 DOM,该值恒为undefined或报错
补充:高 DPI 场景下图片资源的缓存隔离
如果页面内嵌图片需按分辨率出不同 srcset,建议将图片缓存与 HTML 缓存解耦:
- HTML 快照仍按设备类型 + locale + 登录态生成 key
- 图片 URL 自带
@2x或width=参数,CDN 层单独对图片路径 + DPR tag 做二级缓存 - 例如图片请求
/img/banner.jpg?w=750&dpr=2的缓存 key 是img:banner:750:2,与 HTML key 完全分离











