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

如何在Node.js Express REST API中为图片返回304状态码

解决Express返回图片始终200,首次下载后返回304的问题

你的问题核心在于:图片并非存储在本地文件系统,Express默认的静态文件缓存机制(自动生成ETag、处理304响应)无法自动生效,所以得手动实现HTTP缓存逻辑。下面是具体的解决步骤和代码示例:

1. 为图片生成唯一标识(ETag)

ETag是资源的唯一身份标记,用来判断资源是否发生变化。你可以根据实际情况选择生成方式:

  • 如果图片内容永远不会变:直接用图片的唯一ID(比如你示例里的1234)生成即可;
  • 如果图片可能更新:建议用文件内容的哈希值,或者结合数据库中该文件的更新时间戳+唯一ID来生成,确保内容变化时ETag也会变化。

2. 对比缓存验证字段,返回对应状态码

客户端首次请求后,会把ETag存在If-None-Match请求头里。当再次请求时,你需要做两件事:

  • 对比请求头的If-None-Match和你生成的ETag;
  • 如果两者一致,直接返回304 Not Modified,不用发送图片内容;如果不一致,返回图片内容并设置缓存相关响应头。

3. 结合你的代码修改示例

下面是适配你现有路由的具体代码:

router.get('/file/:organisation/:table/:filename', async function (req, res, next) {
  try {
    // 从数据库获取图片数据(假设返回包含内容、唯一ID、更新时间的对象)
    const fileData = await db.resolveTable(req.params.organisation, req.params.table, req.params.filename);
    if (!fileData) {
      return res.status(404).send('File not found');
    }

    // 生成ETag:这里用文件ID+更新时间戳确保内容变化时ETag更新
    const etag = `"${fileData.id}-${fileData.updateTime.getTime()}"`;
    // 如果图片永远不会变,也可以用固定值:const etag = `"${req.params.filename}"`;

    // 检查客户端缓存的ETag是否匹配
    if (req.headers['if-none-match'] === etag) {
      return res.status(304).send();
    }

    // 设置缓存相关响应头
    res.set({
      'ETag': etag,
      'Cache-Control': 'public, max-age=31536000' // 缓存1年,可根据需求调整时长
    });

    // 返回图片内容,自动识别MIME类型
    res.type(req.params.filename.split('.').pop());
    res.send(fileData.content); // 假设fileData.content是图片的Buffer或二进制数据
  } catch (err) {
    next(err);
  }
});

额外补充

  • Cache-Control头可以控制客户端和中间缓存(比如CDN)的策略:public表示允许中间缓存,max-age是缓存的秒数;
  • 除了ETag方案,你也可以用Last-Modified+If-Modified-Since的组合:设置Last-Modified为文件最后更新时间,然后检查请求头的If-Modified-Since是否匹配,匹配则返回304,原理和ETag一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:16:54