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

Express与浏览器缓存头及304响应码行为:为何304显示为200?

问题描述

为了理解缓存头与响应码的行为机制,我编写了两个Express接口进行实验:

第一个接口 /users-a

模拟3000ms数据库查询延迟,返回public, max-age=10的缓存头:

app.get("/users-a", async (req, res) => {
  await new Promise((res) => setTimeout(res, 3000));
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Cache-Control", `public, max-age=10`);
  res.json(users);
});

实验现象:

  • 首次请求耗时3000ms,返回完整响应
  • 10秒内重复请求直接使用浏览器磁盘缓存,耗时极短
  • 响应自动带有Express生成的Etag头:
    Etag: W/"1a-Q1ZzAew6rLbf4JEZbVarkQiSXKo"
    
    后续验证请求会携带If-None-Match头:
    If-None-Match: W/"1a-Q1ZzAew6rLbf4JEZbVarkQiSXKo"
    

第二个接口 /users-b

模拟浏览器持有过期数据时收到304响应的场景:

app.get("/users-b", async (req, res) => {
  res.setHeader("Access-Control-Allow-Origin", "*");

  const ifNoneMatch = req.headers["if-none-match"];

  if (ifNoneMatch && etags.has(ifNoneMatch)) {
    res.sendStatus(304);
  } else {
    await new Promise((res) => setTimeout(res, 3000));

    res.setHeader("Cache-Control", `public, max-age=${10}`);
    res.json(users);

    const etagValue = res.getHeader("etag");
    etags.add(etagValue);
  }
});

实验现象:

  • Express代码确实执行了res.sendStatus(304)逻辑,但浏览器网络面板却显示200响应及响应体,且请求耗时极短。

疑问:这是否是浏览器对304响应码的默认行为——将其转为200显示?

解答

是的,这就是浏览器的默认处理逻辑。

当服务器返回304 Not Modified时,浏览器会自动将该响应映射为200 OK,并展示本地缓存中保存的响应体。这么做的核心目的是简化前端开发:不管是直接读取缓存(显示200 (from cache)),还是通过服务器验证缓存有效后复用(实际收到304但显示200),前端代码拿到的都是一致的状态码和完整响应体,无需额外处理304的特殊场景。

如果想确认服务器真实返回的状态码,可以通过两种方式验证:

  • 在浏览器网络面板的「响应头」或「详情」区域,能看到服务器实际返回的304 Not Modified状态
  • 使用curl命令直接请求接口,会直接看到服务器返回的304状态和响应头

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 20:51:16