跨域请求服务端返回的 304 状态码会被浏览器修改成 200,是浏览器的 BUG 吗

2023-08-03 14:35:34 +08:00
 jiangzm

这个问题仅出现在 Chrome 和 Edge , 也给 chromium 官方提了 Bug 不知道会不会确认是个 BUG 。

1.server code

const express = require('express');
const cors = require('cors');

const app = express();
const port = 3000;

app.use(cors({
  origin: '*',
  allowedHeaders: ['If-None-Match', 'If-Modified-Since'],
  exposedHeaders: ['ETag', 'Last-Modified', 'Cache-Control'],
  maxAge: 86400,
}));

app.get('/getcache', (req, res) => {
  if (req.header('If-None-Match')) {
    return res.status(304).end();
  }

  const time = Date.now();
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('ETag', time);
  res.send(JSON.stringify({ time }));
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

2.client code

fetch('http://localhost:3000/getcache');

在其他网页(跨域)的控制台执行上面 fetch 请求即可,第二次请求后内容没变化但是状态码一直是 200 。用代理软件抓包发现服务端实际响应的是 304 ,在 Safrai 或者 Postman 中请求也是 304 。

如果不是跨域请求,在同域请求 Chrome 是能正常显示 304 状态。

不明白 chrome 会修改这个状态,实际不管是同域还是跨域都支持了协商缓存,状态码为啥要修改成 200 ?

2197 次点击
所在节点    程序员
15 条回复
jiangzm
2023-08-03 14:39:20 +08:00
很早之前就有个感觉 CDN 资源在浏览器中很少显示 304 状态,应该也是和这个问题有关。
sujin190
2023-08-03 14:45:38 +08:00
304 不是未修改可以用缓存。然后浏览器就读缓存成功了,最后给你返回 200 没问题啊,毕竟已经有正确的内容了,是你理解的有问题吧
hepeng10
2023-08-03 14:51:19 +08:00
本来就拿不到 304 ,304 拿到的就是 200 ,网上一堆教程判断 304 的 demo 都是坑
deplivesb
2023-08-03 14:55:03 +08:00
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304

304 表示服务端不需要再次发送资源到客户端,包含隐式重定向。此时 chrome 发现本地存在该资源,自然就 200 啊
wonderfulcxm
2023-08-03 14:55:35 +08:00
@sujin190 那么同域请求怎么会显示 304 了?
jiangzm
2023-08-03 15:08:32 +08:00
@sujin190 #2 原始报文不应该被修改,如果是强缓存直接从本地拿的显示 200 没问题,已经发起了远程请求应该直接显示响应的状态码才对

@hepeng10 #3 304 就是 HTTP 标准定义的怎么可能拿不到 304 , 是不是有点孤陋寡闻了

@deplivesb #4 这个就要看 chromium 怎么定义的这个 200 ,304 确实要读本地缓存,是不是读了缓存(强缓存和协商缓存)统一都是 200 ,就忽略协商缓存过程响应的 304

@wonderfulcxm #5 从来没见过 304 状态吗
jiangzm
2023-08-03 15:10:39 +08:00
1 、同跨正常显示 304


2 、跨域显示 200 、服务端响应是 304


3 、Safrai 跨域请求显示 304
jiangzm
2023-08-03 15:14:14 +08:00
4 、Safrai 跨域请求显示 304 (报文)
jiangzm
2023-08-03 15:17:02 +08:00
如果 chromium 真的是把读了缓存(强缓存和协商缓存)就显示 200 状态, 那同域请求 304 应该也显示 200 才对而不是同域正常显示 304 跨域就改成 200 。 所以应该不是这个规则的原因。 @deplivesb
victimsss
2023-08-03 15:44:53 +08:00
jiangzm
2023-08-03 16:01:10 +08:00
hepeng10
2023-08-03 17:04:07 +08:00
你这么确定能拿到 304 ,我还想看看什么情况下代码中拿到的状态码是 304 ,拿到了 @我一下,谢谢。
我之前就遇到过这个问题,我是没搞出拿到 304 的情况
jiangzm
2023-08-03 19:36:35 +08:00
@hepeng10 #12 http 客户端( ajax/fetch )确实拿到的是 200 ,即使网络面板显示的是 304 。 应该是自动读取了本地缓存,有了响应内容状态就变了。
shansing
2023-08-03 22:45:34 +08:00
没细看,如果真是同域保持 304 跨域转成 200 ,盲猜隐私方面的原因,防止网站猜测用户历史记录、生成指纹之类,跟之前取消超链接 :visited 样式类似。
hepeng10
2023-08-03 23:06:03 +08:00
又问了下 ChatGPT ,这是它的回答:

如果开发者工具中显示的是响应状态码为 304 ,但是在 Ajax 请求的代码中打印出来的是 200 ,这可能是因为浏览器的缓存机制导致的。

当浏览器进行 Ajax 请求时,如果之前已经请求过同一个资源,并且服务器返回了 304 状态码,表示资源未修改,那么浏览器会直接从缓存中获取该资源,并返回 200 状态码。这样做是为了减少网络流量和加快页面加载速度。

实际上,浏览器在处理条件请求(返回 304 )时,对开发者是透明的,这意味着在 Ajax 请求的代码中,你无法直接获取到 304 状态码。浏览器会自动处理缓存,并将从缓存中获取资源后返回 200 状态码。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/962082

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX