http 状态码详解
当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头(server header)用以响应浏览器的请求。
http 状态码分类
分类 | 描述 | 常见状态码 |
---|---|---|
1** | 信息,服务器收到请求 | 101(websocket切换协议) |
2** | 成功,操作被成功接收并处理 | 200(已成功)、202(已经接受请求,但未处理完成) |
3** | 重定向,需要进一步的操作以完成请求 | 301(永久移动)、302(临时移动)、304(未修改,使用缓存) |
4** | 客户端错误,请求包含语法错误或无法完成请求 | 400(客户端请求的语法错误)、401(请求要求用户的身份认证)、403(服务器拒绝执行此请求,一般为无权限)、404(服务器无法根据客户端的请求找到资源) |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 | 500(服务器内部错误,无法完成请求)、503(服务器超负载)、504(充当网关或代理的服务器,未及时从远端服务器获取请求) |
304 状态码与浏览器缓存机制
在一次面试过程中,面试官有提问到 304
状态码以及其背后的浏览器缓存技术,让我对这个状态码印象深刻,下面就来对其进行解析。
304: 所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
请求命中协商缓存时会返回 304
状态码。
浏览器缓存机制
当浏览器请求一个网站的时候,会加载各种各样的资源,比如:HTML文档、图片、CSS和JS等文件。对于一些不经常变的内容,浏览器会将他们保存在本地的文件中,下次访问相同网站的时候,直接加载这些资源,加速访问。
这些被浏览器保存的文件就被称为缓存(不是指Cookie或者Localstorage。
根据请求头部字段不同,浏览器中缓存可分为强缓存和协商缓存:
- 浏览器在加载资源时,先根据这个资源的一些http header判断它是否命中强缓存,强缓存如果命中,浏览器直接从自己的缓存中读取资源,不会发请求到服务器,这种方式是最快的。比如:某个css文件,如果浏览器在加载它所在的网页时,这个css文件的缓存配置命中了强缓存,浏览器就直接从缓存中加载这个css,连请求都不会发送到网页所在服务器;
- 当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,通过服务器端依据资源的另外一些http header验证这个资源是否命中协商缓存,如果协商缓存命中,服务器会将这个请求返回,但是不会返回这个资源的数据,而是告诉客户端可以直接从缓存中加载这个资源,于是浏览器就又会从自己的缓存中去加载这个资源;
- 强缓存与协商缓存的共同点是:如果命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据;区别是:强缓存不发请求到服务器,协商缓存会发请求到服务器。
- 当协商缓存也没有命中的时候,浏览器直接从服务器加载资源数据。
强缓存
当浏览器对某个资源的请求命中了强缓存时,返回的HTTP状态为200,在chrome的开发者工具的network里面 size会显示为from memory cache。
强缓存是利用Expires或者Cache-Control这两个http response header实现的,它们都用来表示资源在客户端缓存的有效期。
- Expires:表示资源过期时间的header,它描述的是一个绝对时间,由服务器返回,用GMT格式的字符串表示,但是当服务器时间与客户端时间相差较大时,缓存管理容易出现问题
- Cache-Control:是一个相对时间,在配置缓存的时候,以秒为单位,用数值表示;如:Cache-Control:max-age=311230000;Cache-Control的常用指令有:
- max-age:从当前请求开始,允许获取的响应被重用的最长时间(单位为秒。例如:Cache-Control:max-age=60表示响应可以再缓存和重用 60 秒。需要注意的是,在max-age指定的时间之内,浏览器不会向服务器发送任何请求,包括验证缓存是否有效的请求。)
- public(允许所有服务器缓存该资源)或 private(禁止中间服务器如代理服务器缓存资源) 标记
- no-cache:浏览器在使用缓存的资源之前,必须先与服务器确认返回的响应是否被更改,如果资源未被更改,可以避免下载。
- 当两种缓存同时启动是Cache-Control优先级高于Expires
协商缓存
当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304并且会显示一个Not Modified的字符串。
协商缓存是利用 Last-Modified
、If-Modified-Since
和 ETag
、If-None-Match
这两对 Header
来管理。
Last-Modified
、If-Modified-Since
和ETag
、If-None-Match
一般都是同时启用,这是为了处理Last-Modified
不可靠的情况
- Last-Modified、If-Modified-Since
- 浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在
response
的header
加上Last-Modified
的header
,表示这个资源在服务器上的最后修改时间。 - 浏览器再次跟服务器请求这个资源时,在
request
的header
上加上If-Modified-Since
的header
,就是上一次请求时返回的Last-Modified
的值。 - 服务器再次收到资源请求时,根据浏览器传过来
If-Modified-Since
和资源在服务器上的最后修改时间判断资源是否有变化,如果没有变化则返回304 Not Modified
,但是不会返回资源内容;如果有变化,就正常返回资源内容,并且更新所对应的全部首部,包括cache-control
、expires
、Date
。 - 浏览器收到
304
的响应后,就会从缓存中加载资源。 - 如果协商缓存没有命中,浏览器直接从服务器加载资源时,
Last-Modified Header
在重新加载的时候会被更新,下次请求时,If-Modified-Since
会启用上次返回的Last-Modified
值。
- 浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在
- ETag、If-None-Match
- 浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在
response
的header
加上ETag
的header
,是服务器根据当前请求的资源生成的一个唯一标识,这个唯一标识是一个字符串,只要资源有变化这个串就不同。 - 浏览器再次跟服务器请求这个资源时,在
request
的header
上加上If-None-Match
的header
,就是上一次请求时返回的ETag
的值。 - 服务器再次收到资源请求时,根据浏览器传过来
If-None-Match
和然后再根据资源生成一个新的ETag
,如果这两个值相同就说明资源没有变化,否则就是有变化;如果没有变化则返回304 Not Modified
,但是不会返回资源内容;如果有变化,就正常返回资源内容。 - 浏览器收到304的响应后,就会从缓存中加载资源。
- 浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在
ETag
、If-None-Match
200 状态码图例
ETag
、If-None-Match
304 状态码图例