V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
jiangzm
V2EX  ›  程序员

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

  •  
  •   jiangzm · 346 天前 · 2005 次点击
    这是一个创建于 346 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这个问题仅出现在 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 ?

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

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

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

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

    @wonderfulcxm #5 从来没见过 304 状态吗
    jiangzm
        7
    jiangzm  
    OP
       345 天前
    1 、同跨正常显示 304


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


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

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

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

    实际上,浏览器在处理条件请求(返回 304 )时,对开发者是透明的,这意味着在 Ajax 请求的代码中,你无法直接获取到 304 状态码。浏览器会自动处理缓存,并将从缓存中获取资源后返回 200 状态码。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2410 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 06:59 · PVG 14:59 · LAX 23:59 · JFK 02:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.