你是否曾经好奇过
浏览器在加载网页时如何处理缓存?在开发者工具的网络(Network)面板中,状态码200和304可能会频繁出现。
这些状态码不仅标志着资源的加载状态,还直接影响网页的加载速度和效率。
在这篇文章中,我们将详细解读HTTP状态码200和304,探索它们在缓存机制中的作用,帮助你理解这些状态码如何影响资源加载和缓存策略。
一、HTTP状态码200与缓存机制
在网络资源的加载过程中,HTTP状态码200扮演着关键角色。它表示服务器成功处理了请求,并返回了请求的资源。这一过程不仅涉及资源的传输,还关系到浏览器如何管理和利用缓存。
具体来说,HTTP状态码200的请求资源主要包括首次请求、内存缓存、磁盘缓存等几种方式。
了解这些缓存机制如何影响资源加载,将帮助我们优化网页性能和用户体验。
1.1 HTTP状态码200详解
HTTP状态码200 OK 表示服务器成功处理了请求,并返回了所请求的资源。
这个状态码是HTTP协议中最常见的成功响应代码,标志着服务器正确完成了请求,并将所请求的数据发送给浏览器。
具体来说,HTTP状态码200的请求资源主要有以下几种表现形式:
1. 请求成功
当浏览器首次请求某个资源时,例如加载一个网页、图片或其他文件,服务器返回200状态码,表示资源已成功传输并且没有问题。
举个例子,当你打开一个新的网页时,浏览器会向服务器请求该网页的HTML、CSS和JavaScript文件,服务器返回200状态码,并传输这些文件到浏览器进行渲染,从而显示出完整的网页内容。
2. 内存缓存
资源成功请求并返回200状态码后,浏览器会将这些资源存储在内存缓存中。
内存缓存是存储在计算机的RAM中的,访问速度非常快,因此适合存储需要频繁访问的资源。
内存缓存的优点在于速度快、能迅速响应用户的请求。然而,它的缺点是内容在浏览器关闭或页面刷新后会被清除,不能长期保存,因此适合用于存储会话期间需要频繁访问的资源。
假设你访问一个新闻网站的首页,其中包含多张图片和样式表。
当你点击某个新闻链接切换到详细页面时,浏览器会利用内存缓存中的图片和样式表来加速页面的加载速度。
这样,即使你在会话中多次切换页面,浏览器也能快速展示这些资源,而不需要重新从服务器下载它们。
内存缓存中的内容在浏览器关闭或页面刷新后通常会被清除。
3. 磁盘缓存
除了内存缓存,浏览器还会将资源存储在磁盘缓存中。
磁盘缓存是存储在计算机的硬盘上的,虽然访问速度比内存缓存慢,但可以长期保存资源,并减少带宽消耗。
磁盘缓存的优点在于可以长期保存资源,即使在浏览器关闭后也能保留。然而,它的缺点是访问速度较慢,无法像内存缓存那样迅速响应用户的请求。因此,磁盘缓存适合用于存储长期需要保留的资源,如图片、样式表和脚本文件等。
例如,当你再次访问之前访问过的网站时,浏览器会从磁盘缓存中读取资源,如网站的图片、样式表和脚本文件,而不是每次都从服务器重新下载这些资源。
假设你访问了一个购物网站,并下载了多个商品图片和样式表。
这些资源会被存储在磁盘缓存中。当你关闭浏览器后再重新访问这个网站时,浏览器会从磁盘缓存中读取这些资源,而不是重新从服务器下载,从而加快页面的显示速度。这种缓存机制帮助减少了重复的网络请求,并提升了用户体验。
1.2 HTTP状态码200与服务器交互情况
在浏览器加载资源的过程中,HTTP状态码200通常表示资源已成功从服务器获取。
在不同的情况下,浏览器的缓存策略会决定是否与服务器进行交互。
以下是三种主要情况:首次请求、内存缓存和磁盘缓存,它们与服务器交互的方式各不相同。
1. 首次请求
当浏览器首次请求一个资源时,例如首次访问一个新的网页或加载一个新的图片,浏览器无法从缓存中找到该资源。此时,浏览器会向服务器发送一个HTTP请求。服务器接收到请求后,处理请求并返回状态码200和所需的资源。
这种情况需要完整的网络请求和响应过程,并且与服务器进行了直接的交互。
运行流程:
flowchart LR
A[浏览器请求资源] --> B{资源在缓存中吗?}
B --> |否| C[向服务器发送HTTP请求]
C --> D[服务器处理请求]
D --> E[服务器返回200状态码和资源]
E --> F[浏览器接收资源并渲染页面]
2. 内存缓存
当浏览器成功请求并返回200状态码后,它会将资源存储在内存缓存中。
如果在同一会话期间再次请求相同的资源,浏览器会首先检查内存缓存。如果资源在内存缓存中,浏览器会直接从内存中加载资源,而无需再次与服务器交互。
这种情况访问速度非常快,因为内存缓存存储在计算机的RAM中,不需要进行网络请求。
运行流程:
flowchart LR
A[浏览器请求资源] --> B{资源在缓存中吗?}
B --> |是, 在内存缓存| C[从内存缓存加载资源]
C --> D[浏览器渲染页面]
3. 磁盘缓存
如果资源不在内存缓存中,浏览器会继续检查磁盘缓存。磁盘缓存是存储在计算机的硬盘上的,如果资源存在于磁盘缓存中,浏览器会直接从磁盘中加载资源,而无需与服务器交互。
这种情况访问速度比内存缓存慢,但依然快于从服务器重新获取资源。磁盘缓存的优点是可以长期保存资源,即使在浏览器关闭后再次打开,资源依然可以从磁盘缓存中加载。
运行流程:
flowchart LR
A[浏览器请求资源] --> B{资源在内存缓存中吗?}
B --> |否| C{资源在磁盘缓存中吗?}
C --> |是| D[从磁盘缓存加载资源]
D --> E[浏览器渲染页面]
4. 与服务器交互的区别
在首次请求的情况下,浏览器必须与服务器进行交互来获取资源,并且服务器会返回状态码200和资源。这是一个完整的HTTP请求-响应循环。
在内存缓存和磁盘缓存的情况下,浏览器不需要与服务器交互,直接从本地缓存中加载资源,这极大地提高了资源加载的速度和用户体验。 但是,如果资源在缓存中不存在或者已过期,浏览器仍然需要与服务器交互来重新获取最新的资源。这时服务器可能会返回200状态码(如果资源需要重新传输),或返回304状态码(如果资源未修改),以此来减少不必要的数据传输。
通过这些缓存机制,浏览器能够有效地管理资源的加载,减少带宽使用,提升网页加载速度和整体用户体验。
二、HTTP状态码304与缓存机制
2.1 HTTP状态码304基本概念
HTTP状态码304 Not Modified 是一种重定向状态码,表示资源未修改,即所请求的资源自上次请求以来没有发生任何变化,这意味着浏览器尝试访问的资源与服务器上当前的版本一致,因此客户端可以继续使用其本地缓存的副本,而不必重新下载。
304状态码与浏览器的缓存机制密切相关,通过使用缓存控制头(如
ETag或Last-Modified)来判断本地缓存的资源是否仍然有效,从而减少不必要的数据传输,提升性能。
2.2 HTTP状态码304的缓存机制
当浏览器请求某个资源时,通常会检查是否在缓存中已经有该资源的副本。如果有,并且资源未过期,则直接从缓存读取使用;如果已过期,浏览器需要向服务器确认资源是否有更新。
浏览器向服务器确认资源是否有更新时,浏览器会将缓存中的 ETag 或 Last-Modified 时间戳包含在请求头中,分别通过 If-None-Match 或 If-Modified-Since 头字段发送给服务器。服务器收到请求后,利用这些头信息来判断资源自上次请求以来是否发生了变化。
ETag是由服务器生成的资源唯一标识符,通常是一个哈希值或唯一的标识符,用于标记资源的版本。在浏览器第二次请求相同资源时,ETag会包含在If-None-Match请求头中发送给服务器。服务器将请求中的ETag值与当前资源的ETag值进行比较。
Last-Modified表示服务器上资源的最后修改时间。当浏览器再次请求相同资源时,会将Last-Modified时间戳包含在If-Modified-Since请求头中发送给服务器。服务器会比较请求中的时间戳与资源的实际最后修改时间。
服务器根据这些头信息的检查结果,作出相应的响应:
-
如果资源未改变:服务器返回
304状态码,并且不包含任何消息体。浏览器则从本地缓存加载资源,并渲染页面。这种方式大大减少了带宽使用量和加载时间,因为不需要重复下载相同的数据。 -
如果资源已改变:服务器返回
200状态码,附带最新的资源内容。浏览器将收到的新数据更新到缓存中,并渲染更新后的内容。
2.3 完整的工作流程
graph TD
A[浏览器请求资源] --> B{资源在缓存中吗?}
B --> |是| C{缓存是否过期?}
C --> |否| D[直接使用缓存资源]
C --> |是| E[浏览器发送带有 If-None-Match 或 If-Modified-Since 的请求到服务器]
E --> F[服务器检查 ETag 或 Last-Modified]
F --> |未修改| G[服务器返回304状态码]
G --> H[浏览器从缓存加载资源]
F --> |已修改| I[服务器返回200状态码和更新后的资源]
I --> J[浏览器更新缓存并渲染新资源]
B --> |否| K[浏览器直接向服务器请求资源]
K --> L[服务器处理请求]
L --> M[服务器返回200状态码和资源]
M --> N[浏览器接收资源并缓存]
N --> O[浏览器渲染页面]
2.4 缓存机制的优势
减少带宽使用:未修改的资源不会重复下载,从而降低了带宽消耗。
提高加载速度:浏览器可以直接从本地缓存中加载资源,从而提升网页的加载速度。
减轻服务器负担:减少了服务器处理请求的频率和数据传输量,提高了服务器的处理效率。
通过上述缓存机制,HTTP 状态码 304 帮助有效减少带宽使用,提升网页性能,并改善用户体验。
三、HTTP状态码304:别担心,我只是来确认一下
我们刚刚讲了状态码200是浏览器和服务器之间的“全套服务”,意思是服务器每次都把整个资源打包发送过来。而状态码304呢,则是“我只是来确认一下”的角色。
它和状态码200最大的不同就在于:304只返回了请求头,而没有返回具体的数据。
3.1 简单来说,304就是个“确认收货”
当浏览器想访问一个资源时,它会先看看自己手上有没有这个资源的缓存副本。如果有,并且这个副本还没有过期,浏览器就直接用本地的缓存资源,根本就不需要去找服务器要。这种情况下,网络流量是零,也就是“满分操作”了。
但是,如果这个缓存副本已经过期了,浏览器就会去问服务器:“嘿,老伙计,我手上的这份资源你有没有更新过?”——这时候,浏览器会发出一个带有验证信息的请求。服务器收到请求后,去自己的仓库查一查,看这个资源有没有变化。如果资源没有变化,服务器就会回应说:“没问题,你手上的还是最新的!状态码304!”然后,浏览器就会放心大胆地使用自己手上的那份缓存。
3.2 为啥304这么重要?省流量,提速度!
你可能会问,为什么不每次都让服务器发一份新的数据呢?因为这样做太浪费了!如果每次都发新的数据,不仅会增加服务器的负担,还会浪费很多网络流量。状态码304的存在,就是为了避免这些浪费。
想象一下,你每天上班路过同一个广告牌,这个广告牌上的内容几乎从来不变。你会每次都花时间去仔细看一遍吗?当然不会!如果没换过,你就一瞥带过就好了。状态码304就像是这个“一瞥”,它让浏览器快速地确认手上的缓存资源还有效,从而提高网页的加载速度,减少服务器的工作量。
3.3 小结:200和304的区别就在这儿
状态码200:服务器说,“好吧,既然你要,那我就把所有数据都给你发一份新的。”(全量传输)
状态码304:服务器说,“不必了,你手上那份就是最新的,不用再浪费时间和流量了。”(省流量,验证有效)
小白:小黑,我能看看你昨天给我的那份文件吗?
小黑:小白,我昨天不是已经给你了吗?你要是手上有,就用那个吧!
- - - - - - - - - - - - - - - - - - - - - - - -
小白:小黑,我手上有昨天的文件,但我不确定有没有更新。我猜你没改过,是不是?
小黑:靠,你明知道还来问我?(304)
- - - - - - - - - - - - - - - - - - - - - - - -
小白:小黑,我手上有昨天的文件,但我不确定有没有更新。我猜你没改过,是不是?
小黑:小白,嘿嘿,其实我加了一些新内容!(200)
3.4 状态码304是怎样帮助提升性能的?
减少数据传输:304状态码不会把完整的资源数据再发一遍,减少了数据的传输量。
节省带宽:因为减少了不必要的数据传输,304可以大大节省服务器和客户端之间的带宽消耗。
提高加载速度:少了数据传输的时间,网页加载速度自然就更快了。
所以,状态码304就是浏览器和服务器在进行聪明合作的一种方式。通过这个“小动作”,大大提高了我们日常上网的效率和体验。
四、强缓存与协商缓存:让缓存机制更高效
在上一部分中,我们已经聊到了浏览器是如何通过 200 和 304 状态码来优化资源加载的。接下来,我们要深入探讨 强缓存 和 协商缓存 这两个核心概念,它们分别在什么场景下发挥作用,怎样让浏览器缓存机制变得更加高效。
4.1 强缓存:保证资源的“快速直达”
强缓存 是一种浏览器完全依赖于缓存数据的机制。它告诉浏览器:“在我设置的时间范围内,你可以完全信任我给的缓存资源,无需再向服务器确认。”
强缓存可以通过以下两种方式实现:
Cache-Control:这是 HTTP/1.1 引入的一种缓存控制机制,支持多种指令来控制缓存行为。例如:
Cache-Control: max-age=3600表示资源在缓存中可以存储 3600 秒(1小时)而不需要重新请求。Cache-Control: no-cache则强制每次都进行验证,虽有缓存,但需重新向服务器验证。
Expires:这是 HTTP/1.0 中的缓存机制,指定一个绝对时间戳,表示资源的过期时间。例如:
Expires: Wed, 21 Oct 2024 07:28:00 GMT表示资源在该时间之前均为有效。
当这些强缓存设置生效时,浏览器将直接从缓存中读取资源,并返回 200 (from memory cache) 或 200 (from disk cache) 状态码,这就像是浏览器完全“听从”了服务器的安排,执行了“快速直达”操作。
4.2 协商缓存:服务器的“再确认”
协商缓存 则是一种稍微复杂的机制,要求浏览器在使用缓存资源前向服务器进行一次“确认”。这就像是浏览器在每次使用缓存时,都需要问问服务器:“这份资源还是最新的吗?”
协商缓存通过以下头部来实现:
ETag:服务器为资源生成的唯一标识符。如果资源内容没有变化,ETag 值保持不变。当浏览器携带 ETag 进行请求时,服务器可以通过比较来确认资源是否更新。
例如:浏览器请求时发送
If-None-Match: "123456", 服务器确认资源没有变化时,返回304 Not Modified。
Last-Modified:记录资源最后修改的时间。当浏览器发送请求时,会带上 If-Modified-Since 头部,服务器根据时间判断资源是否变更。
例如:浏览器请求时发送
If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT,如果资源没有修改,服务器返回304 Not Modified。
当协商缓存生效时,服务器的响应是 304 Not Modified,表示资源没有变化,浏览器继续使用本地缓存资源。
4.3 强缓存与协商缓存的区别
强缓存:完全由浏览器依赖本地缓存资源,不会与服务器进行通信。常见的状态码有 200 (from memory cache 内存缓存) 和 200 (from disk cache 磁盘缓存)。
协商缓存:浏览器每次使用缓存资源时都会向服务器确认,服务器返回 304 Not Modified 表示资源没有变化,浏览器继续使用缓存。
在实际使用中,强缓存的优先级高于协商缓存。如果资源在强缓存有效期内,浏览器就直接使用缓存,不会进行协商请求。当强缓存失效或需要验证时,才会进行协商缓存的检查。
4.4 实际应用中的缓存策略
了解了强缓存和协商缓存的区别后,我们可以更好地应用这些缓存策略。
例如,静态资源如图片、CSS 文件可以使用较长的强缓存时间,以减少网络请求;而动态内容或经常变化的数据则适合使用协商缓存,以确保用户获得最新信息。
通过合理配置缓存策略,我们可以优化资源加载速度,减轻服务器负担,提高用户体验。
五、强缓存与协商缓存的实际应用场景
在实际开发中,了解和合理应用强缓存与协商缓存策略,可以显著提高应用的性能和用户体验。接下来,我们探讨这两种缓存策略的实际应用场景,并解释它们在现代前端项目(例如使用 Vue 3 + TypeScript + Vite 的项目)中的应用方式。
5.1 强缓存与协商缓存的实际应用场景
5.1.1 强缓存
适用于那些不常变动的资源,比如静态文件(如图片、CSS 和 JavaScript 文件)。
这些资源通常是经过优化的,且内容在一段时间内不会发生变化。通过设置适当的缓存头(如 Cache-Control 或 Expires),可以让浏览器将这些资源缓存起来,从而在后续的请求中直接使用缓存内容,而不需要再次向服务器请求。
这种方式可以减少网络流量,缩短加载时间,提高页面性能。例如,网站中的 Logo 图片或公共样式表通常会设置较长的缓存时间。
5.1.2 协商缓存
适用于那些可能会发生变化的资源,如 HTML 文件或某些动态生成的内容。
即便这些资源的内容偶尔会变动,浏览器也会根据缓存的验证信息(如 Last-Modified 或 ETag)向服务器确认资源是否已更新。服务器会根据资源的变化情况返回相应的状态码(如 304 Not Modified),告知浏览器是否可以继续使用本地缓存的资源。
这样,即使资源发生变化,浏览器也能确保用户获取到最新的内容,同时避免不必要的重复下载。
5.2 在现代前端项目中的应用
在现代前端开发中,尤其是使用如 Vue 3、TypeScript 和 Vite 这样的工具链时,缓存策略的应用有以下特点:
5.2.1 资源标识
现代构建工具(如 Vite)通常会在打包过程中生成带有哈希值的文件名(如 main.abc123.js等)。这种做法确保了文件名的唯一性。
当文件内容发生变化时,哈希值也会随之改变,浏览器就会识别为一个新的资源,而不是使用旧的缓存。 这种策略使得强缓存可以有效地工作,提高资源加载效率。
5.2.2 HTML 文件的缓存
对于 HTML 文件,虽然其内容可能会变化,但通常不会使用带哈希值的文件名。在这种情况下,协商缓存变得尤为重要。浏览器在请求 HTML 文件时,会携带 Last-Modified 或 ETag 等头部信息,服务器则根据这些信息返回最新的资源状态。
这样,浏览器可以确保每次加载的 HTML 文件都是最新的,同时避免频繁从服务器下载不必要的内容。
5.2.3 静态资源与动态内容
静态资源(如 JavaScript、CSS 和图片)可以通过强缓存提高加载性能,而动态内容(如 HTML 文件或用户生成的数据)则需要依赖协商缓存来确保数据的新鲜度。
这种组合使用强缓存与协商缓存的策略,使得应用在性能和数据准确性之间取得平衡。
六、如何使用 Nginx 实现对静态资源的缓存策略
在现代前端开发中,Nginx 作为一个高性能的 Web 服务器,被广泛用于处理静态资源的请求。通过合理配置 Nginx 的缓存策略,我们可以显著提升应用的加载速度和性能。
下面我们将讲解如何使用 Nginx 实现对静态资源的强缓存和协商缓存策略。
6.1 使用 Nginx 配置强缓存策略
强缓存策略的目标是告诉浏览器在指定时间内直接使用缓存中的资源,而不去请求服务器。我们可以通过设置 Cache-Control 和 Expires 响应头来实现。
server {
listen 80;
server_name example.com;
location / {
# 配置静态文件的缓存策略
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
# 添加 Cache-Control 头,指定强缓存时间为 30 天
expires 30d;
add_header Cache-Control "public, max-age=2592000";
}
# 针对 HTML 文件,不使用强缓存
location ~* \.(html)$ {
expires -1;
add_header Cache-Control "no-cache";
}
# 其他配置
root /usr/share/nginx/html;
index index.html index.htm;
}
}
在上述配置中:
对于图片(
jpg、jpeg、png、gif、ico)和静态文件(css、js),我们设置了Cache-Control为public并指定max-age=2592000(即 30 天),同时设置了expires为30d。这意味着这些资源在 30 天内都将从缓存中加载,不会再向服务器发起请求。对于 HTML 文件,我们设置了
Cache-Control为no-cache和expires -1。这意味着每次请求 HTML 文件时,浏览器都会向服务器确认文件是否有更新,避免使用过期的 HTML 文件。
6.2 使用 Nginx 配置协商缓存策略
协商缓存策略依赖于浏览器和服务器之间的通信,确保浏览器使用的缓存是最新的。我们可以通过配置 Last-Modified 和 ETag 响应头来实现。
server {
listen 80;
server_name example.com;
location / {
# 针对所有静态文件启用协商缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|html)$ {
# 打开文件的 Last-Modified 头部
add_header Last-Modified $date_gmt;
add_header Cache-Control "public, max-age=0, must-revalidate";
# 使用 ETag 头进行资源比对
etag on;
# 设置过期时间为0,强制浏览器每次请求时进行协商缓存检查
expires -1;
}
root /usr/share/nginx/html;
index index.html index.htm;
}
}
在上述配置中:
使用
$date_gmt动态设置Last-Modified响应头,这个头部表示文件最后修改的时间。浏览器会在下次请求时,带上If-Modified-Since请求头,服务器根据这个头部判断资源是否有更新。
etag on;启用 ETag,ETag 是资源的一个唯一标识符(通常是文件内容的哈希值),用于精确地判断文件是否有变化。当文件未改变时,服务器返回304 Not Modified状态码,浏览器可以继续使用缓存。设置
expires -1来明确指定资源不应使用强缓存,而是依赖于协商缓存来确保最新性。
6.3 Nginx 缓存策略的最佳实践
小而频繁更新的资源(如 HTML 文件):使用协商缓存策略来确保每次请求获取到的都是最新的内容。
大而不常变动的资源(如图片、JS、CSS 文件):使用强缓存策略来减少不必要的网络请求,提高加载速度。
混合策略:可以根据项目需要,灵活配置不同类型资源的缓存策略。例如,可以为静态资源(JS、CSS、图片)设置较长的强缓存时间,而对可能经常变化的内容(HTML 文件)使用协商缓存策略。
通过合理配置 Nginx 的缓存策略,可以充分利用浏览器的缓存机制,减少服务器压力,加快页面加载速度,提升用户体验。在现代前端开发中,缓存策略是优化性能的关键手段之一。