HTTP之200还是304?

开发 前端
本文和大家探讨HTTP之200还是304?

[[345737]]

当浏览器第一次加载资源的时候,返回一般为200,意思是成功获取资源,并会在浏览器的缓存中记录下max-age,第二次访问的时候:如果只是用浏览器打开,那么浏览器会去判断这个资源在缓存里有没有,如果有的话,会去判断max-age,看看过期没有,如果没有过期,则直接读缓存,根本不会和服务器进行交互,换句话说,断网都能打开,就和本地跑一样!如果已经过期了,那就去服务器请求,等待服务器响应,这是很费时间的,服务器如果发现资源没有改变过,那么就会返回304,告诉浏览器,我没变过,你去读缓存吧,于是浏览器也不用从服务器拉数据了,然而,等待服务器响应也是一个很要命的问题,在网速发达的今天,等一个响应,有时比下载还慢。如果是用浏览器刷新的,那么浏览器不会去判断max-age了,直接去服务器拿,如果服务器判断资源没变过,则还是会返回304,和上面是一样的,所以刷新一下,其实很可怕,等于把所有的资源都要去服务器请求一边,问问服务器我过期了没有。

浏览器在第一次请求资源的时候,服务端响应头里可以设置expires字段,该字段表示该资源的缓存过期时间,第二次请求的时候,如果时间还在该缓存时间之内,则会直接使用缓存,否则重新加载资源, 这个expires字段有个缺陷,就是它必须服务端和客户端的时间严格同步才能生效,所以现在很多人不会使用改方案。另外一种方案是第一次请求资源的时候,服务端设置响应头cache-control: max-age,这样设置的意思是告诉浏览器,这个资源什么时候过期,等第二次请求资源的时候,判断是否超出了过期时间,如果没超出,直接使用缓存。

缓存状态码 200 OK (from cache) 与 304 Not Modified

  • 200 OK (from cache) 是浏览器没有跟服务器确认,直接用了浏览器缓存;
  • 304 Not Modified 是浏览器和服务器多确认了一次缓存有效性,再用的缓存。

304 Not Modified:客户端有缓冲的文件并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。

304 Not Modified 比 200 OK (from cache) 慢,指的是浏览器还向服务器确认了下 “If-Not-Modified”,才用的缓存

200和304特点

  • 状态码200:请求已成功,请求所希望的响应头或数据体将随此响应返回。即返回的数据为全量的数据,如果文件不通过GZIP压缩的话,文件是多大,则要有多大传输量。
  • 状态码304:如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。即客户端和服务器端只需要传输很少的数据量来做文件的校验,如果文件没有修改过,则不需要返回全量的数据。

状态为304的请求要比状态为200的请求的数据量小很多,因为304只需要返回响应头,并不需要返回整个文件,所以只需要几字节就可以了,这样能够节省大量的网络带宽,并减少了页面的渲染时间。

什么是浏览器缓存?
浏览器缓存是为了节约网络的资源加速浏览,浏览器在用户磁盘上对最近请求过的文档进行存储,当访问者再次请求这个页面时,浏览器就可以从本地磁盘显示文档,这样就可以加速页面的阅览。浏览器缓存主要包括强缓存和协商缓存。-- 百度百科

浏览器缓存也称为http缓存。

通俗地说,浏览器缓存指的是浏览器为了节省网络资源及加快页面渲染,将请求过的资源缓存在本地(硬盘和内存中),再根据http响应头来判断是否读取本地的缓存资源。

缓存HTTP头信息

  • Date:原服务器发送该资源响应报文的时间(GMT格式)
  • Age:Age表示这个响应已经存活了多久了(HTTP/1.0的响应不带Age)
  • Expires:即在 HTTP 头中指明具体失效的时间(HTTP/1.0),Expires = HTTP-date
  • Pragma:no-cache,每次请求页面时都不要读缓存,兼容HTTP/1.0,优先级高于Expires(HTTP/1.0 + HTTP/1.1)
  • Cache Control:优先级高于Pragma、Expires(HTTP/1.1) 【public,客户端和服务端都可以缓存;private,只能客户端缓存;no-store,不使用缓存;no-cache,使用协商缓存。】

Expires

  • Expires是http1.0提出的一个表示资源过期时间的header,它描述的是一个绝对时间,由服务器返回。
  • Expires第二次请求时,将和本地时间比对。
  • Expires 第一次请求服务器是,响应头会返回一个Expires的文件过期时间。
  • Expires 第二次请求,客户端使用本地时间和文件的过期时间进行比对,如果文件未过期则直接使用本地缓存,返回状态码200(from memory cache)或200(from disk cache)。

Expires Cache-Control

  • Cache-Control: no-cache 必须先与代理服务器确认是否更改,然后在在决定使用缓存还是请求,类似于协商缓存(304)
  • Cache-Control: no-store 才是真正的不缓存数据到本地
  • Cache-Control: public 可以被所有用户缓存(多用户共享),包括终端和CDN等中间代理服务器
  • Cache-Control: private 只能被终端浏览器缓存(而且是私有缓存),不允许中继缓存服务器进行缓存
  • Cache-Control: must-revalidate如果缓存内容失效,请求必须发送服务器进行验证
  • Cache-Control: max-age=s 缓存内容在s秒后失效,仅HTTP1.1可用 max-gae 第一次请求服务器时,响应头会返回一个 max-age,是文件多少时间后过期。max-gae 第二次请求,客户端会校验文件是否过期,如果文件未过期则直接使用本地缓存,返回状态码200(from memory cache)或200(from disk cache)。

强缓存(200 from disk cache 或者 200 from memory cache, 硬盘缓存和内存缓存)
强缓存指的是浏览器缓存了该请求的资源且根据缓存标识(响应头的cache-control:max-age 及 expires)判定资源未过期。

协商缓存(304)
协商缓存指的是浏览器缓存了该请求的资源但未能判断资源是否过期,需要向服务器发起携带缓存标识(响应头的 last-modified 及 Etag)的请求来询问资源是否过期。

浏览器缓存相关响应头
强缓存相关

Expires
Expires 是 HTTP/1.0 中控制浏览器缓存的字段,其值为服务器返回的该请求结果缓存的到期时间。当浏览器再次发起请求时,如果客户端时间早于到期时间,则直接读取缓存结果而不用再次发起请求。

因为这边用到了客户端的时间进行判断,所以可能会因为客户端时间和服务器时间不同导致预期之外的缓存行为

Cache-Control
cache-control 是HTTP/1.1 的字段,是控制缓存的重要规则,它的值包含了几组可选的值,中间使用逗号相隔开

  1. 控制代理服务器缓存
  • public:所有内容被缓存(代理服务器和客户端都可缓存)
  • private(默认):仅客户端可缓存
  1. 控制是否缓存
  • no-cache:客户端缓存内容,是否使用缓存需要与服务器进行协商
  • no-store:所有内容不会被缓存
  1. 控制缓存有效期
  • max-age:其值为资源的有效时间(秒),表示缓存将在xx秒后失效

当 max-age 和 expires 同时存在时,只有 max-age 有效,expires 将不再生效

协商缓存相关

last-modified
last-modified 用于标识资源的最新修改时间,用于标记内容是否更新。

响应头的 last-modified 会作为缓存标识一起存储与缓存中,当再次请求需要进行服务器协商时,请求头的 if-Modified-Since 字段将带上缓存中的 last-modified 的值与服务器的资源修改时间进行比较,判断缓存是否过期。

使用 last-modified 有可能出现服务器资源未产生实质性更新但是修改时间更新的情况,比如资源重写。

Etag
Etag 是服务器根据资源内容通过一系列算法计算得出的用于标识资源的字符串编码,当资源内容有修改时,对应的 Etag 也会更新。其主要功能就是用于标记资源内容是否更新。

同样的,响应头的 Etag 会作为缓存标识一起存储于缓存中,当再次请求需要进行服务器协商时,请求头的 if-None-Match 字段将带上缓存中的 etag 值与服务器上资源的 Etag 进行比较,判断缓存是否过期。

Etag 和 last-modified 同时出现时,以 Etag 的标识为准。

浏览器缓存相关的请求头
Cache-Control

  • no-cache:强制向源服务器再次验证,控制代理服务器不能直接返回缓存
  • max-age:响应的最大age值,可以设置max-age=0使用协商缓存

last-modified-since
配合 last-modified 使用

if-None-Match
配置 Etag 使用

完整的浏览器缓存过程

  1. 判断本地是否有缓存,如果本地没有缓存资源则进入第4步,如果有则进入第2步。
  2. 通过 expires 和 max-age 判断缓存是否过期,如果未过期则直接返回资源(200 from cache)。否则进入第3步。
  3. 携带缓存标识(if-modified-since if-None-Match)进行请求,与服务器协商验证缓存是否过期,如果未过期则服务器返回不带资源实体的响应,浏览器从缓存中获取资源并返回给前端(304),否则进入第4步。

      4.正常请求资源,服务器返回资源(200)并进行缓存。

缓存相关知识点
缓存的位置
浏览器缓存的存储位置分为硬盘(disk cache)和内存(memory cache),浏览器的读取顺序为内存->硬盘。

不同的资源可能会缓存在不同的位置

  1. css:因为 css 解析构建 CSSOM 树之后就不需要使用了,所以会被缓存在硬盘中,读取时从硬盘读取。
  2. JS 和图片:因为浏览器解析JS和图片之后,会将其放在内存中,所以优先读取内存(实践证明并非一定),当打开新窗口或者浏览器时则读取硬盘缓存。

不同的用户行为导致的缓存问题
刷新(F5/Command+r)
刷新时会给文档请求头加上 Cache-Control:max-age=0,所以文档一般会触发协商缓存。而文档之外的其他资源(JS css)则正常请求(可能会触发强缓存或协商缓存)。

强制刷新(CTRL + F5/Command+shift+r/勾选disable cache)
强制刷新时会给请求头加上 Cache-control:no-cache,使用协商缓存,但同时会删除协商缓存字段(if-modified-since if-none-match),所以最终结果都是从服务器请求新资源。

关闭浏览器/打开新标
没有特殊操作,有可能使用强缓存或协商缓存。

责任编辑:姜华 来源: JavaScript忍者秘籍
相关推荐

2021-05-30 09:25:48

HttpETag 网络协议

2017-09-28 12:03:40

前端

2019-09-23 08:35:52

2011-06-10 12:44:09

2020-03-24 15:15:29

HttpClientOkHttpJava

2012-04-10 17:37:57

2022-06-01 22:30:15

滑动容器堆叠容器

2022-05-31 14:32:23

Stack堆叠容器

2014-06-18 09:25:07

HTTP

2022-07-12 17:03:43

鸿蒙网络请求库

2021-02-07 19:02:46

TCPIP HTTP

2013-01-03 14:49:34

BES黑莓移动安全

2011-03-28 09:49:44

nagioscheck_http

2016-11-28 09:00:10

浏览器浏览器缓存服务端

2016-10-11 22:24:47

移民计划飞船火星

2022-11-08 09:17:21

2016-09-27 20:36:23

微信HttpWeb

2011-09-13 13:27:50

LG投影仪

2012-06-20 13:56:48

投影仪行情

2009-04-21 11:25:10

视频通讯Express 200LifeSize
点赞
收藏

51CTO技术栈公众号