这个问题仅出现在 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 ?
1
jiangzm OP 很早之前就有个感觉 CDN 资源在浏览器中很少显示 304 状态,应该也是和这个问题有关。
|
2
sujin190 2023-08-03 14:45:38 +08:00 via Android
304 不是未修改可以用缓存。然后浏览器就读缓存成功了,最后给你返回 200 没问题啊,毕竟已经有正确的内容了,是你理解的有问题吧
|
3
hepeng10 2023-08-03 14:51:19 +08:00
本来就拿不到 304 ,304 拿到的就是 200 ,网上一堆教程判断 304 的 demo 都是坑
|
4
deplivesb 2023-08-03 14:55:03 +08:00
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304
304 表示服务端不需要再次发送资源到客户端,包含隐式重定向。此时 chrome 发现本地存在该资源,自然就 200 啊 |
5
wonderfulcxm 2023-08-03 14:55:35 +08:00
@sujin190 那么同域请求怎么会显示 304 了?
|
6
jiangzm OP @sujin190 #2 原始报文不应该被修改,如果是强缓存直接从本地拿的显示 200 没问题,已经发起了远程请求应该直接显示响应的状态码才对
@hepeng10 #3 304 就是 HTTP 标准定义的怎么可能拿不到 304 , 是不是有点孤陋寡闻了 @deplivesb #4 这个就要看 chromium 怎么定义的这个 200 ,304 确实要读本地缓存,是不是读了缓存(强缓存和协商缓存)统一都是 200 ,就忽略协商缓存过程响应的 304 @wonderfulcxm #5 从来没见过 304 状态吗 |
7
jiangzm OP |
8
jiangzm OP |
9
jiangzm OP 如果 chromium 真的是把读了缓存(强缓存和协商缓存)就显示 200 状态, 那同域请求 304 应该也显示 200 才对而不是同域正常显示 304 跨域就改成 200 。 所以应该不是这个规则的原因。 @deplivesb
|
10
victimsss 2023-08-03 15:44:53 +08:00
|
11
jiangzm OP @victimsss #10 这个问题应该很早就有,看之前别人提的 issue 有的状态都 fixed ,不知道为啥最新版还是有这个问题
bug list: https://bugs.chromium.org/p/chromium/issues/list?q=304%20status%20code&can=1 bug fixed: https://bugs.chromium.org/p/chromium/issues/detail?id=1351286&q=304%20status%20code&can=1 stackoverflow: https://stackoverflow.com/questions/61584984/chrome-shows-200-ok-status-in-network-even-if-server-returns-304 |
12
hepeng10 2023-08-03 17:04:07 +08:00
你这么确定能拿到 304 ,我还想看看什么情况下代码中拿到的状态码是 304 ,拿到了 @我一下,谢谢。
我之前就遇到过这个问题,我是没搞出拿到 304 的情况 |
13
jiangzm OP @hepeng10 #12 http 客户端( ajax/fetch )确实拿到的是 200 ,即使网络面板显示的是 304 。 应该是自动读取了本地缓存,有了响应内容状态就变了。
|
14
shansing 2023-08-03 22:45:34 +08:00
没细看,如果真是同域保持 304 跨域转成 200 ,盲猜隐私方面的原因,防止网站猜测用户历史记录、生成指纹之类,跟之前取消超链接 :visited 样式类似。
|
15
hepeng10 2023-08-03 23:06:03 +08:00
又问了下 ChatGPT ,这是它的回答:
如果开发者工具中显示的是响应状态码为 304 ,但是在 Ajax 请求的代码中打印出来的是 200 ,这可能是因为浏览器的缓存机制导致的。 当浏览器进行 Ajax 请求时,如果之前已经请求过同一个资源,并且服务器返回了 304 状态码,表示资源未修改,那么浏览器会直接从缓存中获取该资源,并返回 200 状态码。这样做是为了减少网络流量和加快页面加载速度。 实际上,浏览器在处理条件请求(返回 304 )时,对开发者是透明的,这意味着在 Ajax 请求的代码中,你无法直接获取到 304 状态码。浏览器会自动处理缓存,并将从缓存中获取资源后返回 200 状态码。 |