V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
xiaoz
V2EX  ›  问与答

请教一下关于浏览器(HTTP)缓存的问题

  •  
  •   xiaoz · 2019-07-25 17:56:16 +08:00 · 1880 次点击
    这是一个创建于 1980 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如这张图片: https://f002.backblazeb2.com/file/test-imgurl/imgs/2019/07/085f80437d5da3bd_thumb.jpg 是存放在 B2 的,已经设置了Cache-Control: max-age=6000,但是发现浏览器每次刷新都是返回的 200 状态码,而不是 304,浏览器并没有缓存这张图片,这是哪个 header 影响导致的呢?还是其它原因?

    13 条回复    2019-07-25 20:21:42 +08:00
    meik2333
        1
    meik2333  
       2019-07-25 18:10:26 +08:00   ❤️ 1
    etag 和 last-modified 至少要提供一个吧,不然无法判断照片是否被修改过。
    1KN6sAqR0a57no6s
        2
    1KN6sAqR0a57no6s  
       2019-07-25 18:14:10 +08:00 via Android
    因为你直接在地址栏输入的图片地址,用 img 标签加载试试。
    xiaoz
        3
    xiaoz  
    OP
       2019-07-25 18:42:15 +08:00 via Android
    @YuxiangLuo 但是你访问这张图片试试 https://cdn.xiaoz.me/wp-content/uploads/2019/07/snipaste_20190721_155819.png 也是直接访问图片,再次刷新是可以返回 304 的。
    Itanium
        4
    Itanium  
       2019-07-25 18:52:45 +08:00
    以 etag 为例,这个需要服务器告诉浏览器是否取缓存
    客户端存下 etag,然后在 headers 里加上 if-none-match 再把服务器给的 etag 传回去,如果图片没发生改变 etag 不会变,服务器返回 304 让浏览器从本地缓存取
    JK9993
        5
    JK9993  
       2019-07-25 18:55:39 +08:00
    chrome 缓存了也会返回 200
    Cynic222
        6
    Cynic222  
       2019-07-25 19:05:18 +08:00 via iPhone
    你要看是不是 from cache
    limuyan44
        7
    limuyan44  
       2019-07-25 19:11:11 +08:00
    你没发现这 2 个图片请求头和返回头都不一样吗
    gbin
        8
    gbin  
       2019-07-25 19:29:56 +08:00   ❤️ 1
    #5 说的对。
    如果 HTTP 响应头被设置了 `Cache-Control: max-age=6000`,在缓存的有效期内,也就是 6000 秒内,HTTP 请求不对缓存的资源做新鲜度校验,而是直接返回 200。如果你想每次都对缓存资源做新鲜度校验,那么你可以设置成 no-store (或者设置 must-revalidate ),no-store 的意思是不建议直接使用缓存而不是不使用缓存,这种情况下,HTTP 请求会配合 ETag + If-Modified 等多个请求头对资源校验,如果资源没有被更改服务器才会返回 304,告诉客户端资源没有被修改,可以直接取本地缓存。
    gbin
        9
    gbin  
       2019-07-25 19:50:41 +08:00   ❤️ 1
    @gbin #8 不建议直接使用缓存是 no-cache,no-store 是禁止使用缓存
    wszgrcy
        10
    wszgrcy  
       2019-07-25 20:04:18 +08:00 via Android
    有强制缓存和协商缓存
    gbin
        11
    gbin  
       2019-07-25 20:05:10 +08:00
    你给的两张图片为什么返回的值一个是 200 一个是 304?
    这是因为两张图片的 Request Headers 中设置了 max-age=0,这是客户端告诉服务器本地缓存过期时间是 0,但是这并不是说客户端不能缓存,而是说每次请求都需要做新鲜度校验,如果资源没有被修改就返回 304 客户端取本地缓存,否则返回 200。第一张图片服务器没有返回 ETag 标志,再次请求的时候客户端无法比对成功,所以返回了 200 (猜测是后端动态生成的缩略图?),第二张请求时返回了 ETag 标志,再此请求时使用 if-none-match 和 ETag 比对,if-modified-since 和 last-modified 比对,如果都比对成功说明资源没有被修改,所以客户端直接取缓存。
    gbin
        12
    gbin  
       2019-07-25 20:19:35 +08:00
    另外还有一个点就是 #2 说的,为什么你直接浏览器输入 URL 和使用 img 标签呈现效果不一样,
    比如 https://0x400.com/2019-07-10-lc-67-add-binary.html 这个连接中有一张图片,如果你直接刷新页面你会看到图片是 from disk 或者 from cache,也就是命中缓存了,此时返回的就是 200. 但是如果你直接在浏览器中输入图片的 url,你会发现返回的是 304,这就是因为 Chrome 的 Reload 操作会主动携带 max-age=0 的请求头对图片做新鲜度校验。
    meik2333
        13
    meik2333  
       2019-07-25 20:21:42 +08:00   ❤️ 2
    @YuxiangLuo #2
    @JK9993 #5
    @gbin #11

    他们说的对,Chrome 如果本地缓存了,状态是 200 (from disk cache) 或者 200 (from memory cache),在 Chrome 中如果直接通过 URL 打开图片的话,会在 Request 中添加 cache-control: max-age=0 来让缓存不生效( https://superuser.com/questions/313131/how-do-i-stop-chrome-sending-cache-control-max-age-0-when-i-hit-enter ),因此如果需要测试 cache-control 是否生效的话,需要用 img 标签加载。

    然后就是为什么他是 304 你是 200 的问题了,这个就是我刚才说的,因为你没有给 etag 和 last-modified。但是如果使用 img 标签加载的话,你们两个的图片都是可以被缓存的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3003 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 13:52 · PVG 21:52 · LAX 05:52 · JFK 08:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.