video标签缓存由服务端响应头决定而非HTML属性;需在Node.js/Express中设置no-store、移除ETag,Nginx中配置expires -1和etag off,并在前端调用load()强制刷新。

为什么 video 标签加 cache-control: no-cache 没用
浏览器对 的缓存行为不由 HTML 属性控制,而是由服务器返回的 HTTP 响应头决定。即使你在 HTML 里写 ,只要服务端响应头带 Cache-Control: public, max-age=3600,浏览器仍会缓存。关键在服务端配置,不是前端加参数或属性。
Node.js/Express 中禁用视频缓存的正确写法
在提供视频文件的路由中,必须显式设置响应头,并确保不被后续中间件覆盖。常见错误是只设了 Cache-Control 却漏掉 ETag 和 Last-Modified——这两个字段一旦存在,浏览器可能仍发起条件请求(304 Not Modified),导致“看似没重载实则用了缓存”。
- 务必移除
ETag:用res.removeHeader('ETag') - 禁用协商缓存:设
res.set('Cache-Control', 'no-store, must-revalidate') - 避免时间戳欺骗:不要依赖客户端传的
?t=xxx参数,它无法阻止服务端返回可缓存响应头
app.get('/video/:id', (req, res) => {
const filePath = path.join(__dirname, 'videos', req.params.id);
res.removeHeader('ETag');
res.set({
'Cache-Control': 'no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0'
});
res.sendFile(filePath);
});Nginx 配置视频路径禁用缓存
如果视频走静态文件服务(比如 Nginx 直接 serve /videos/),需在 location 块中覆盖默认缓存策略。注意:不能只写 add_header,必须配合 expires 和 etag off,否则 add_header 可能被忽略或与内置逻辑冲突。
-
expires -1表示立即过期(比0更可靠) -
etag off强制关闭 ETag 生成 - 避免使用
if ($request_filename ~* \.mp4$)做条件判断——Nginx 的if在 location 内不可靠
location /videos/ {
alias /var/www/static/videos/;
expires -1;
add_header Cache-Control "no-store, must-revalidate, max-age=0";
etag off;
}前端 fallback:强制刷新 src 并清除 MediaElement 缓存
即便服务端配置正确,某些浏览器(尤其是 iOS Safari)对 的 src 切换有内部缓冲机制。单纯改 src 值(如加时间戳)不够,还需调用 load() 并监听 canplay,否则可能复用旧解码器状态。
立即学习“前端免费学习笔记(深入)”;
- 改
src后必须调用video.load(),不能只靠 DOM 更新 - 避免重复调用
load()导致卡顿;可在onstalled或onerror时再触发 - 移动端注意:iOS Safari 不支持
URL.createObjectURL(new Blob(...))动态生成视频 URL 后直接播放,会静音或失败
const video = document.getElementById('myVideo');
video.src = '/video/clip.mp4?t=' + Date.now();
video.load(); // 必须显式调用
video.addEventListener('canplay', () => {
video.play();
}, { once: true });服务端响应头才是决定性因素,前端加参数只是辅助手段;no-store 比 no-cache 更彻底,而 etag off 和 expires -1 是容易被忽略的硬性配套操作。











