前端面试:如何设计兼顾隐私与缓存的响应式图片 Client Hints 方案?
题干与适用场景
一个内容站点要在手机、平板和桌面端提供不同宽度与 DPR 的图片。产品希望降低首屏流量,CDN 又担心按每个 Width、DPR 建缓存导致缓存碎片;法务要求只收集必要的设备信息。请设计方案,并说明不支持 Client Hints 时如何工作、如何避免 CLS 与重复下载、如何验证收益。
适合考察浏览器资源选择、HTTP 缓存、性能、可访问性和渐进增强。题设中的宽度、DPR、流量均为待测变量,不应凭空承诺固定百分比收益。
面试官在考察什么
- 能否用
srcset/sizes描述真实渲染槽位,让浏览器在客户端选候选图。 - 能否把
Accept-CH、后续请求、Vary和 CDN 缓存键连成完整数据流。 - 能否识别高基数 Client Hints 的隐私、指纹和缓存爆炸风险。
- 能否设计无 JavaScript 依赖的回退、尺寸占位、
alt与测量闭环。
先澄清哪些问题
- 图片是内容图、装饰图还是需要艺术裁切的 Hero?不同用途决定
alt与 picture 元素策略。 - 图片槽位在各断点的 CSS 宽度和比例是多少?
sizes必须描述槽位,不能只写视口宽度。 - CDN 是否支持按规范化宽度、格式和质量参数建键?允许多少候选宽度?
- 目标浏览器对 Client Hints、现代图片格式和响应式预加载的支持范围是什么?
- 首屏指标、缓存命中率、图片字节数和错误率的基线如何采集?
30 秒回答框架
先用 HTML 原生响应式图片解决大多数请求,再把 Client Hints 作为服务器/CDN 的渐进增强。浏览器用 srcset 与 sizes 选择候选图;服务器若根据提示改变响应,就声明 Accept-CH,并让缓存策略体现真正影响响应的字段。只允许白名单宽度与 DPR 桶,保留安全默认值、尺寸占位和无提示回退。最后以 LCP、CLS、图片字节、命中率和错误率做对照实验,并检查高熵提示是否真的必要。
分步作答
1. 先定义候选集与槽位
为每张图生成有限宽度集合,例如 320、640、960、1280(示例值,不代表通用标准),并保留原始比例。sizes 按布局断点表达预计显示宽度;浏览器还会结合 DPR、网络和自身策略选择候选。src 作为必要回退。
<img
src="/img/card-640.jpg"
srcset="/img/card-320.jpg 320w, /img/card-640.jpg 640w, /img/card-960.jpg 960w, /img/card-1280.jpg 1280w"
sizes="(min-width: 66rem) 33vw, (min-width: 44rem) 50vw, 100vw"
width="640"
height="400"
alt="文章封面"
loading="lazy"
decoding="async"
>2. 用 picture 处理格式和艺术方向
需要 WebP/AVIF 等格式或移动端不同裁切时使用 picture 元素,最后仍放一个带 src 的 img 元素回退。格式选择与宽度选择分层,避免用一个固定 preload 误导浏览器下载错误资源。
3. 设计 Client Hints 的最小闭环
响应可通过 Accept-CH 请求服务器真正使用的提示,例如 DPR 或 Width;浏览器是否发送、何时发送受自身设置、权限策略和支持情况影响。服务器收到提示后必须忽略不认识的字段,并只将确实改变响应的字段纳入缓存变化说明。
Accept-CH: DPR, Width
Vary: Accept, DPR, WidthVary 只是语义声明,不等于可无限扩展缓存。对 Width 先映射到有限桶,对 DPR 进行规范化,或把规范化结果纳入 CDN 键;不把原始任意查询参数直接拼进上游 URL。
4. 处理隐私、权限与安全输入
Client Hints 是请求元数据,不是身份凭证。优先使用低熵且确实有用的提示,避免请求设备型号等高熵字段来做个体画像。宽度、质量、格式参数必须做范围校验和白名单映射,图片转换服务还要阻止 SSRF、开放重定向和超大尺寸消耗。
5. 保留渐进增强与可访问性
没有 Client Hints、提示未获允许或 CDN 未命中时,仍由 srcset/sizes 和服务器默认宽度完成加载。为图片提供 width、height 或等价的比例盒,降低 CLS;首屏 LCP 图谨慎使用 loading="eager" 或 fetchpriority="high",折叠下方图片才懒加载;内容图写有意义的 alt。
6. 建立可回滚的测量
按相同内容与流量切分对照组,记录 LCP、INP、CLS、图片传输字节、解码耗时、命中率、错误率、实际显示宽度和设备类别。若命中率下降或重复下载增加,先减少提示维度、扩大宽度桶或撤回 Client Hints,而不是继续增加缓存变体。
高质量示范答案
我会把浏览器原生选择放在第一层:给图片有限的 srcset 候选和准确的 sizes,并设置尺寸属性与可访问的 alt。需要格式或艺术裁切时使用 picture 元素,img 元素仍提供可靠回退。服务器可以通过 Accept-CH 请求实际用于变体选择的提示,但我会把它当作可缺省输入:首个请求、未获权限或不支持时仍返回安全默认图。
如果响应会因提示改变,我会让 CDN 的键只包含规范化的宽度、DPR 桶、格式和质量白名单;Vary 只声明真正影响响应的字段。因为原始 Width 和网络提示可能有高基数,不能直接为每个值建缓存。设备型号等高熵信息没有业务必要就不请求,也不把提示当认证条件。最后用 LCP/CLS、字节、命中率和错误率做同内容 A/B,确认没有重复下载后再逐步扩大覆盖。
常见失分点
- 把
sizes写成永远的100vw,忽略多列布局,导致过大的候选图。 - 只讲
Accept-CH,不讲后续请求、权限、Vary和缓存键。 - 对每个原始宽度、DPR、网络值建立 CDN 变体,造成缓存碎片。
- 依赖客户端 JavaScript 先测量再请求,牺牲首屏和离线回退。
- 用固定 preload link 覆盖响应式选择,触发错误或重复下载。
- 忽略
alt、尺寸占位、参数白名单和高熵提示的隐私风险。
追问与参考回答
Vary 是不是越多越正确?
不是。它应准确反映会改变可缓存响应的请求字段;高基数字段会增加变体并降低命中率。可以先做规范化键,或改用有限服务端默认策略。
为什么已经有 srcset 还要 Client Hints?
srcset/sizes 让浏览器掌握槽位并自主选择,通常是首选。Client Hints 只在服务器/CDN 必须依据设备或网络元数据生成响应时补充,且不能取代回退。
第一个 HTML 请求就一定带 Width 吗?
不应这样假设。Accept-CH 的协商影响后续请求,提示发送还受浏览器支持和权限策略影响,因此首个请求必须可独立工作。
如何判断缓存键桶是否太细?
观察命中率、变体数量、边缘存储占用和每个桶的请求量;把相邻宽度合并后比较字节与 LCP,若收益小于缓存成本就收敛桶数。
什么时候不应使用高熵提示?
当业务只需粗粒度宽度、格式或省流偏好时。设备型号等字段会增加指纹面和缓存维度,不能因为“可能有用”就默认开启。
如何测试预加载不会重复下载?
在支持响应式预加载的浏览器和回退浏览器分别抓取网络记录,确认 preload 与最终 img 元素选择同一 URL;不支持时让 HTML 的 srcset 成为唯一可靠路径。