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

如何在Express中间件中为静态资源启用ETag,为JSON请求禁用ETag?

解决Express中静态资源启用ETag、JSON请求禁用ETag的问题

这个场景很典型——ETag对静态资源的缓存优化价值很高,但动态JSON响应往往需要每次返回完整内容,避免304 Not Modified导致客户端拿不到最新数据的问题。下面是两种简洁的实现方案,不用手动逐个检查请求头:

方案一:通过响应Content-Type自动拦截(推荐)

我们可以写一个中间件,拦截所有响应,当检测到响应是JSON类型时,自动移除ETag头。这种方式更可靠,不管请求头有没有指定Accept: application/json,只要后端返回JSON,就会禁用ETag:

// 保持全局启用ETag的原有配置
app.enable('etag');

// 自定义中间件处理JSON响应的ETag
app.use((req, res, next) => {
  // 保存原始的res.send方法
  const originalSend = res.send;
  
  res.send = function(body) {
    // 检查当前响应的Content-Type是否为JSON
    if (res.get('Content-Type')?.includes('application/json')) {
      // 移除ETag头,跳过304校验逻辑
      res.removeHeader('ETag');
      // 额外设置Cache-Control,确保客户端不缓存JSON
      res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
    }
    // 调用原始send方法发送响应
    return originalSend.call(this, body);
  };
  
  next();
});

// 静态资源配置(默认继承全局ETag设置,无需额外修改)
app.use(express.static('public'));

方案二:基于请求Accept头提前禁用ETag

如果你的业务场景中,只有明确请求JSON的客户端才需要禁用ETag,可以在请求阶段直接判断Accept头,提前关闭ETag功能:

app.enable('etag');

app.use((req, res, next) => {
  // 如果请求期望JSON响应,禁用ETag生成
  if (req.accepts('json')) {
    res.etag = false; // Express会识别该属性,跳过ETag生成逻辑
    res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
  }
  next();
});

app.use(express.static('public'));

补充说明

  • 为什么JSON请求要禁用ETag?动态JSON数据通常随业务逻辑变化,304会导致客户端获取不到最新内容;而静态资源(图片、CSS、JS)内容稳定,ETag能有效减少重复请求,节省带宽。
  • 静态资源的ETag会自动生效,因为express.static默认继承全局的ETag配置,无需额外单独开启。

内容的提问来源于stack exchange,提问作者Alexander Mills

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:52:37