前言
在不那么遥远的一些年以前,一个在江湖中行走的前端,只需要了解“前端三剑客”就足以找到一份工作。很多前端只限于 CSS,HTML、JS
,网络基础,数据结构之类的都不甚了解。不过这个时期的前端也是最受鄙视的时期,这个时期前端的大量工作依赖于后端,且不需要动画效果和交互效果。
现如今前端圈已经发生翻天覆地的变化,Vue,React,ES6,HTML5,CSS3,Webpack, PostCss
等技术层出不穷。作为一个有格局的前端,对网络基础定是要了然于心的。
如果你对网络基础还不太了解,以下的内容可以给你提供一个思路;如果你对此已经了然于心,以下的内容烦请批评指正。
入题
任何事物的诞生,最初都是服务于极少数人的。渐渐地被这极少数人推而广之,我们大众就开始接触了解它,互联网是如此,麻将亦是如此。不管是互联网还是麻将,它们都增强了人与人之间的交流。
接下来我会讲以下内容:
- 五层因特网协议栈
- HTTP 与 HTTPS 的区别
- TCP/IP 协议
- 五类 IP 地址
- DNS 域名解析
- 三次握手和四次挥手
- 跨域的原因及处理方式
- 正向代理和反向代理
- CDN 带来的性能优化
- HTTP 强缓存&协商缓存
五层因特网协议栈 TOP
一、应用层
应用层( application-layer )的任务是通过应用进程间的交互来完成特定网络应用。应用层协议定义的是应用进程(进程:主机中正在运行的程序)间的通信和交互的规则。对于不同的网络应用需要不同的应用层协议。在互联网中应用层协议很多,如域名系统 DNS,支持万维网应用的 HTTP 协议,支持电子邮件的 SMTP 协议等等。
我们把应用层交互的数据单元称为报文
域名系统
域名系统( Domain Name System )是因特网的一项核心服务,它作为可以将域名和 IP 地址相互映射的一个分布式数据库,能够使人更方便的访问互联网,而不用去记住能够被机器直接读取的 IP 数串。
http 协议
超文本传输协议( HyperText Transfer Protocol )是互联网上应用最为广泛的一种网络协议。所有的 WWW(万维网) 文件都必须遵守这个标准。
二、传输层
传输层(transport layer)的主要任务就是负责向两台主机进程之间的通信提供通用的数据传输服务。应用进程利用该服务传送应用层报文。
传输层常用的两种协议
- 传输控制协议-TCP:提供面向连接的,可靠的数据传输服务。
- 用户数据协议-UDP:提供无连接的,尽最大努力的数据传输服务(不保证数据传输的可靠性)。
TCP(Transmisson Control Protocol)
- TCP 是面向连接的(需要先建立连接);
- 每一条 TCP 连接只能有两个端点,每一条 TCP 连接只能是一对一;
- TCP提供可靠交付的服务。通过TCP连接传送的数据,无差错、不丢失、不重复、并且按序到达;
- TCP 提供全双工通信。TCP 允许通信双方的应用进程在任何时候都能发送数据。TCP 连接的两端都设有发送缓存和接收缓存,用来临时存放双方通信的数据;
- 面向字节流。TCP 中的“流”(Stream)指的是流入进程或从进程流出的字节序列。
UDP(User Datagram Protocol)
- UDP 是无连接的;
- UDP 使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的链接状态;
- UDP 是面向报文的;
- UDP 没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如直播,实时视频会议等);
- UDP 支持一对一、一对多、多对一和多对多的交互通信;
- UDP 的首部开销小,只有 8 个字节,比 TCP 的 20 个字节的首部要短。
- 单工数据传输只支持数据在一个方向上传输
- 半双工数据传输允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;
- 全双工数据通信允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。
三、网络层
网络层的任务就是选择合适的网间路由和交换结点,确保计算机通信的数据及时传送。在发送数据时,网络层把运输层产生的报文段或用户数据报封装成分组和包进行传送。在 TCP/IP 体系结构中,由于网络层使用 IP 协议,因此分组也叫 IP 数据报 ,简称数据报。
互联网是由大量的异构(heterogeneous)网络通过路由器(router)相互连接起来的。互联网使用的网络层协议是无连接的网际协议(Intert Prococol)和许多路由选择协议,因此互联网的网络层也叫做网际层或 IP 层。
四、数据链路层
数据链路层(data link layer)通常简称为链路层。两台主机之间的数据传输,总是在一段一段的链路上传送的,这就需要使用专门的链路层的协议。
在两个相邻节点之间传送数据时,数据链路层将网络层接下来的 IP 数据报组装成帧,在两个相邻节点间的链路上传送帧。每一帧包括数据和必要的控制信息(如同步信息,地址信息,差错控制等)。
在接收数据时,控制信息使接收端能够知道一个帧从哪个比特开始和到哪个比特结束。
五、物理层
在物理层上所传送的数据单位是比特。 物理层(physical layer)的作用是实现相邻计算机节点之间比特流的透明传送,尽可能屏蔽掉具体传输介质和物理设备的差异。使其上面的数据链路层不必考虑网络的具体传输介质是什么。“透明传送比特流”表示经实际电路传送后的比特流没有发生变化,对传送的比特流来说,这个电路好像是看不见的。
在互联网使用的各种协中最重要和最著名的就是 TCP/IP 两个协议。
和 OSI 七层协议模型、TCP/IP 四层模型的区别
-
OSI 七层模型
OSI七层协议模型主要是:
应用层(Application)、表示层(Presentation)、会话层(Session)、传输层(Transport)、网络层(Network)、数据链路层(Data Link)、物理层(Physical)。
-
TCP/IP四层模型
TCP/IP是一个四层的体系结构,主要包括:
应用层、传输层、网络层和链路层。
各层对应
以下一张图很好的说明了这三种协议的区别
![](https://camo.githubusercontent.com/3918ca05f272132922dbe0b1a508533773c815bed121eae14bc3210574f9f2b2/68747470733a2f2f757365722d676f6c642d63646e2e786974752e696f2f323031392f322f31332f313638653439333732656564636233323f773d36353226683d33343326663d7765627026733d3231313834)
HTTP 与 HTTPS 的区别 TOP
区别 |
HTTP |
HTTPS |
协议 |
运行在 TCP 之上,明文传输,客户端与服务器端都无法验证对方的身份 |
身披 SSL( Secure Socket Layer )外壳的 HTTP,运行于 SSL 上,SSL 运行于 TCP 之上, 是添加了加密和认证机制的 HTTP。 |
端口 |
80 |
443 |
资源消耗 |
较少 |
由于加解密处理,会消耗更多的 CPU 和内存资源 |
开销 |
无需证书 |
需要证书,而证书一般需要向认证机构购买 |
加密机制 |
无 |
共享密钥加密和公开密钥加密并用的混合加密机制 |
安全性 |
弱 |
由于加密机制,安全性强 |
对称加密与非对称加密
对称密钥加密是指加密和解密使用同一个密钥的方式,这种方式存在的最大问题就是密钥发送问题,即如何安全地将密钥发给对方;
而非对称加密是指使用一对非对称密钥,即公钥和私钥,公钥可以随意发布,但私钥只有自己知道。发送密文的一方使用对方的公钥进行加密处理,对方接收到加密信息后,使用自己的私钥进行解密。
由于非对称加密的方式不需要发送用来解密的私钥,所以可以保证安全性;但是和对称加密比起来,非常的慢.
综上:我们还是用对称加密来传送消息,但对称加密所使用的密钥我们可以通过非对称加密的方式发送出去。
TCP/IP 协议 TOP
负责传输的 IP 协议
按层次分,IP(Internet Protocol)网际协议位于网络层,IP 协议的作用是把各种数据包传送给对方。而要保证确实传送到对方那里,则需要满足各类条件,其中两个重要的条件是 IP 地址和 MAC 地址(Media Access Control Address)。
IP 地址和 MAC 地址: 指明了节点被分配到的地址,MAC 地址是指网卡所属的固定地址,IP 地址可以和 MAC 地址进行配对。IP 地址可变换,但 MAC 地址基本上不会更改。
使用 ARP 协议凭借 MAC 地址进行通信
- IP 间的通信依赖 MAC 地址。
- ARP 是一种用以解释地址的协议,根据通信方的 IP 地址就可以反查出对应方的 MAC 地址。
TCP 协议如何保持传输的可靠性
TCP提供一种面向连接的、可靠的字节流服务。
1. 面向连接
意味着两个使用 TCP 的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个 TCP 连接。在一个 TCP 连接中,仅有两方进行彼此通信;
2. 字节流服务
意味着两个应用程序通过 TCP 链接交换 8bit 字节构成的字节流,TCP 不在字节流中插入记录标识符。
TCP 之所以可靠,大体上由于以下原因:
- 数据包校验:目的是检测数据在传输过程中的任何变化,若校验出包有错,则丢弃报文段并且不给出响应,这时 TCP 发送数据端超时后会重发数据;
- 对失序数据包重排序:既然 TCP 报文段作为 IP 数据报来传输,而 IP 数据报的到达可能会失序,因此 TCP 报文段的到达也可能会失序。TCP 将对失序数据进行重新排序,然后才交给应用层;
- 丢弃重复数据:对于重复数据,能够丢弃重复数据;
- 应答机制:当 TCP 收到发自 TCP 连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒;
- 超时重发:当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段;
- 流量控制:TCP 连接的每一方都有固定大小的缓冲空间。TCP 的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制。
TCP/IP 通信传输流
借用图解 HTTP 一书中的图文:
![](https://camo.githubusercontent.com/b15d84a0b4c82b811c0e121955579c0a3e3a38106fd7261bdaf441cb919888ce/68747470733a2f2f757365722d676f6c642d63646e2e786974752e696f2f323031392f322f31332f313638653461336432626539323761623f773d38383626683d36373226663d6a70656726733d3433383532)
发送端在层与层之间传输数据时,每经过一层必定会加上一个该层的首部信息。反之,接收端在层与层之间传输数据时,每经过一层会把相关的首部信息去掉。
五类 IP 地址 TOP
网络地址:用于识别主机所在的网络;
主机地址:用于识别该网络中的主机。
IP地址分为五类:
- A 类保留给政府机构
- B 类分配给中等规模的公司
- C 类分配给任何需要的人
- D 类用于组播
- E 类用于实验
各类可容纳的地址数目不同。其中A类、B类、和C类这三类地址用于TCP/IP节点,其它两类D类和E类被用于特殊用途。
一. A类地址
第一个八位段为网络地址,其它为主机地址,第一个八位段首位一定为0;
范围:1.0.0.1—126.155.255.254;
私有地址和保留地址:
10.X.X.X是私有地址(所谓的私有地址就是在互联网上不使用,而被用在局域网络中的地址)。
127.X.X.X是保留地址,用做循环测试用的。
二. B类地址
第一个八位段和第二个八位段为网络地址,其它为主机地址,第一个八位段首位一定为10;
范围:128.0.0.1—191.255.255.254。
私有地址和保留地址:
172.16.0.0—172.31.255.255是私有地址
169.254.X.X是保留地址。如果你的IP地址是自动获取IP地址,而你在网络上又没有找到可用的DHCP服务器。就会得到其中一个IP。
三. C类地址
前三个八位段为网络地址,第4个个字节为主机地址,第一个八位段首位一定为110。
范围:192.0.0.1—223.255.255.254。
私有地址:
192.168.X.X是私有地址。
四. D类地址
不分网络地址和主机地址,第一个八位段首位一定为1110。
范围:224.0.0.1—239.255.255.254
五. E类地址
不分网络地址和主机地址,第一个八位段首位一定为11110。
范围:240.0.0.1—255.255.255.254
DNS 域名解析 TOP
当你在浏览器的地址栏输入 https://juejin.im
后会发生什么,大家在心中肯定是有一个大概的,这里我将 DNS 域名解析 这个步骤详细的讲一遍。在讲概念之前我先放上一张经典的图文供大家思考一分钟。
![](https://camo.githubusercontent.com/e3d3921c0cfedf85eca2e7e96f942cf6d2036c5c61e93c0c03effc6cefd91d16/68747470733a2f2f757365722d676f6c642d63646e2e786974752e696f2f323031392f322f31392f313639303561343832623262613936333f773d39393426683d35383026663d706e6726733d313838323635)
查找域名对应的 IP 地址的聚体过程
- 浏览器搜索自己的 DNS 缓存(浏览器维护一张域名与 IP 地址的对应表);如果没有命中,进入下一步;
- 搜索操作系统中的 DNS 缓存;如果没有命中,进入下一步;
- 搜索操作系统的 hosts 文件( Windows 环境下,维护一张域名与 IP 地址的对应表);如果没有命中,进入下一步;
- 操作系统将域名发送至 LDNS (本地区域名服务器),LDNS 查询自己的 DNS 缓存(一般命中率在 80% 左右),查找成功则返回结果,失败则发起一个迭代 DNS 解析请求:
- LDNS向 Root Name Server(根域名服务器,如com、net、im 等的顶级域名服务器的地址)发起请求,此处,Root Name Server 返回 im 域的顶级域名服务器的地址;
- LDNS 向 im 域的顶级域名服务器发起请求,返回 juejin.im 域名服务器地址;
- LDNS 向 juejin.im 域名服务器发起请求,得到 juejin.im 的 IP 地址;
- LDNS 将得到的 IP 地址返回给操作系统,同时自己也将 IP 地址缓存起来;操作系统将 IP 地址返回给浏览器,同时自己也将 IP 地址缓存起来。
DNS Prefetch
即 DNS 预获取,是前端优化的一部分。一般来说,在前端优化中与 DNS 有关的有两点:
- 减少 DNS 的请求次数
- 进行 DNS 预获取
典型的一次 DNS 解析需要耗费 20-120 毫秒,减少DNS解析时间和次数是个很好的优化方式。DNS Prefetching 是让具有此属性的域名不需要用户点击链接就在后台解析,而域名解析和内容载入是串行的网络操作,所以这个方式能减少用户的等待时间,提升用户体验。
TCP 三次握手和四次挥手 TOP
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的 RFC793 定义。
三次握手
![](https://camo.githubusercontent.com/f4778915dfe9df8da465bb1dfc9682e840db40d47a67a9f8952c43bb25b216ec/68747470733a2f2f757365722d676f6c642d63646e2e786974752e696f2f323031392f322f32302f313639306235306633663337333938323f773d3131313526683d34393426663d706e6726733d3334353836)
第一次握手:
建立连接时,向服务器发出连接请求报文,这是报文首部中的同部位 SYN = 1,同时选择一个初始序列号 seq = x ,客户端进程进入了 SYN-SENT (同步已发送状态)状态,等待服务器确认;
第二次握手:
服务器收到 syn 包后,如果同意连接,则发出确认报文; 确认报文 ACK = 1,SYN = 1,确认号是 ack = x + 1,同时也要为自己初始化一个序列号 seq = y,此时服务器进程进入了 SYN-RCVD(同步收到)状态;
第三次握手:
客户端收到服务器的 SYN+ACK 包,要向服务器给出确认。确认报文的 ACK = 1,ack = y + 1,自己的序列号 seq = x + 1,此时,TCP 连接建立,客户端进入 ESTABLISHED (已建立连接)状态。
完成三次握手,客户端与服务器开始传送数据。
注:
seq:"sequance" 序列号;
ack:"acknowledge" 确认号;
SYN:"synchronize" 请求同步标志;
ACK:"acknowledge" 确认标志;
FIN:"Finally" 结束标志。
未连接队列
在三次握手协议中,服务器维护一个未连接队列,该队列为每个客户端的SYN包(syn=j)开设一个条目,该条目表明服务器已收到SYN包,并向客户发出确认,正在等待客户的确认包。这些条目所标识的连接在服务器处于 Syn_RECV状态,当服务器收到客户的确认包时,删除该条目,服务器进入ESTABLISHED状态。
建立一个连接需要三次握手,而终止一个连接要经过四次握手,这是由 TCP 的半关闭(half-close)造成的。
四次挥手
![](https://camo.githubusercontent.com/18e4dee5a765f714350349b3800c5828b53cd82b13358d0a04e719a88ed76ebd/68747470733a2f2f757365722d676f6c642d63646e2e786974752e696f2f323031392f322f32302f313639306235343038363730383662363f773d3130363626683d35343226663d706e6726733d3531333034)
第一次挥手:
客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部 FIN=1,其序列号为 seq = u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入 FIN-WAIT-1(终止等待1)状态。
第二次挥手:
服务器收到连接释放报文,发出确认报文,ACK = 1,ack = u + 1,并且带上自己的序列号 seq = v,此时,服务端就进入了 CLOSE-WAIT(关闭等待)状态。
TCP 服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个 CLOSE-WAIT 状态持续的时间。
客户端收到服务器的确认请求后,此时,客户端就进入 FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
第三次挥手:
服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN = 1,ack = u + 1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为 seq = w,此时,服务器就进入了 LAST-ACK(最后确认)状态,等待客户端的确认。
第四次挥手:
客户端收到服务器的连接释放报文后,必须发出确认,ACK = 1,ack = w + 1,而自己的序列号是 seq = u + 1,此时,客户端就进入了 TIME-WAIT(时间等待)状态。
注意此时 TCP 连接还没有释放,必须经过 2MSL(最长报文段寿命)的时间后,当客户端撤销相应的 TCB 后,才进入 CLOSED 状态。
服务器只要收到了客户端发出的确认,立即进入 CLOSED 状态。同样,撤销 TCB 后,就结束了这次的 TCP 连接。
可以看到,服务器结束 TCP 连接的时间要比客户端早一些。
四次的原因
这是因为服务端的 LISTEN 状态下的 SOCKET 当收到 SYN 报文的建连请求后,它可以把 ACK 和 SYN(ACK 起应答作用,而 SYN 起同步作用)放在一个报文里来发送。 但关闭连接时,当收到对方的 FIN 报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你未必会马上会关闭 SOCKET ,也即你可能还需要发送一些数据给对方之后,再发送 FIN 报文给对方来表示你同意现在可以关闭连接了,所以它这里的 ACK 报文和 FIN 报文多数情况下都是分开发送的.
由于 TCP 连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个 FIN 来终止这个方向的连接。收到一个 FIN 只意味着这一方向上没有数据流动,一个 TCP 连接在收到一个 FIN 后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
跨域的原因及处理方式 TOP
出现跨域的原因是由于浏览器的同源策略 所决定的。
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
这个说法一如既往的很官方,犹如女神的一句 呵呵,让人不知所以然。接下来就从 Dom 查询和接口请求来说明同源策略的必要性。
接口请求
我们来看场景:
1.你准备去清空你的购物车,于是打开了买买买网站 www.maimaimai.com
,然后登录成功,一看,购物车东西这么少,不行,还得买多点。
2.你在看有什么东西买的过程中,你的好基友发给你一个链 接 www.nidongde.com
,一脸坏笑地跟你说:“你懂的”,你毫不犹豫打开了。
3.你饶有兴致地浏览着 www.nidongde.com
,谁知这个网站暗地里做了些不可描述的事情!由于没有同源策略的限制,它向 www.maimaimai.com
发起了请求!暗地里为所欲为的做一些为所欲为的事情。
Dom 查询
1.有一天你刚睡醒,收到一封邮件,说是你的银行账号有风险,赶紧点进 www.yinghang.com
改密码。你吓尿了,赶紧点进去,还是熟悉的银行登录界面,你果断输入你的账号密码,登录进去看看钱有没有少了。
2.睡眼朦胧的你没看清楚,平时访问的银行网站是 www.yinhang.com
,而现在访问的是 www.yinghang.com
,这个钓鱼网站做了什么呢?
// HTML
<iframe name="yinhang" src="www.yinhang.com"></iframe>
// JS
// 由于没有同源策略的限制,钓鱼网站可以直接拿到别的网站的Dom
const iframe = window.frames['yinhang']
const node = iframe.document.getElementById('你输入账号密码的Input')
console.log(`拿到了这个${node},我还拿不到你刚刚输入的账号密码吗`)
由此我们知道,同源策略确实能规避一些危险,不是说有了同源策略就安全,只是说同源策略是一种浏览器最基本的安全机制,毕竟能提高一点攻击的成本。其实没有刺不穿的盾,只是攻击的成本和攻击成功后获得的利益成不成正比。
跨域解决方案
- 通过jsonp跨域
- document.domain + iframe跨域
- location.hash + iframe
- window.name + iframe跨域
- postMessage跨域
- 跨域资源共享(CORS)
- nginx代理跨域
- nodejs中间件代理跨域
- WebSocket协议跨域
具体的方案请看前端常见跨域解决方案(全)
正向代理和反向代理 TOP
正向代理
- 代理客户;
- 隐藏真实的客户,为客户端收发请求,使真实客户端对服务器不可见;
- 一个局域网内的所有用户可能被一台服务器做了正向代理,由该台服务器负责 HTTP 请求;
- 意味着同服务器做通信的是正向代理服务器;
反向代理
- 代理服务器;
- 隐藏了真实的服务器,为服务器收发请求,使真实服务器对客户端不可见;
- 负载均衡服务器,将用户的请求分发到空闲的服务器上;
- 意味着用户和负载均衡服务器直接通信,即用户解析服务器域名时得到的是负载均衡服务器的 IP ;
共同点
- 都是做为服务器和客户端的中间层
- 都可以加强内网的安全性,阻止 web 攻击
- 都可以做缓存机制
具体的应用可以看我写的这一篇文章 【前端词典】和媳妇讲代理后的意外收获
CDN 带来的性能优化 TOP
HTTP 强缓存&协商缓存 TOP
缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当 web 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。
这样带来的好处是缓解服务器端压力,提升性能(获取资源的耗时更短了)。对于网站来说,缓存是达到高性能的重要组成部分。
缓存大致可归为两类:私有缓存与共享缓存。
共享缓存能够被多个用户使用;
私有缓存只能用于单独用户;
HTTP
协议主要是通过请求头当中的一些字段来和服务器进行通信,从而采用不同的缓存策略。
HTTP
通过缓存将服务器资源的副本保留一段时间,这段时间称为新鲜度限值。这在一段时间内请求相同资源不会再通过服务器。HTTP
协议中 Cache-Control
和 Expires
可以用来设置新鲜度的限值。
强缓存 ( Cache-Control 和 Expires )
强缓存主要是采用响应头中的 Cache-Control
和 Expires
两个字段进行控制的。
其中 Expires
是 HTTP 1.0
中定义的,它指定了一个绝对的过期时期。而 Cache-Control
是 HTTP 1.1
时出现的缓存控制字段。
Cache-Control:max-age
定义了一个最大使用期。 就是从第一次生成文档到缓存不再生效的合法生存日期。由于Expires是HTTP1.0时代的产物,因此设计之初就存在着一些缺陷,如果本地时间和服务器时间相差太大,就会导致缓存错乱。
这两个字段同时使用的时候 Cache-Control
的优先级给更高一点。
这两个字段的效果是类似的,客户端都会通过对比本地时间和服务器生存时间来检测缓存是否可用。如果缓存没有超出它的生存时间内,客户端就会直接采用本地的缓存。如果生存日期已经过了,这个缓存也就宣告失效。接着客户端将再次与服务器进行通信来验证这个缓存是否需要更新。
Cache-Control
通用消息头字段被用于在 http
请求和响应中通过指定指令来实现缓存机制。
可缓存性
public
:响应可以被任何对象(客户端、代理服务器等)缓存
private
:只能被单个用户缓存,不能作为共享缓存
no-cache
:使用缓存副本之前,需要将请求提交给原始服务器进行验证,验证通过才可以使用
only-if-cached
:客户端只接受已缓存的响应,并且不向原始服务器检查是否有更新的拷贝
到期
max-age=<seconds>
:缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与 Expires
相反,时间是相对于请求的时间
s-maxage=<seconds>
:覆盖 max-age
或者 Expires
头,但是仅适用于共享缓存(比如各个代理),并且私有缓存中它被忽略
max-stale[=<seconds>]
:表明客户端愿意接收一个已经过期的资源。可选的设置一个时间(单位秒),表示响应不能超过的过时时间
min-fresh=<seconds>
:表示客户端希望在指定的时间内获取最新的响应
重新验证和重新加载
must-revalidate
:缓存必须在使用之前验证旧资源的状态,并且不可使用过期资源。
proxy-revalidate
:与 must-revalidate
作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略
其他
no-store
:彻底得禁用缓冲,本地和代理服务器都不缓冲,每次都从服务器获取
no-transform
:不得对资源进行转换或转变。Content-Encoding
, Content-Range
, Content-Type
等 HTTP
头不能由代理修改。
示例:
// 禁止缓存:
Cache-Control: no-cache, no-store, must-revalidate
// 缓存静态资源文件:
Cache-Control:public, max-age=31536000
协商缓存 ( Last-Modified 和 Etag )
协商缓存机制下,浏览器需要向服务器去询问缓存的相关信息,进而判断是重新发起请求、下载完整的响应,还是从本地获取缓存的资源。
如果服务端提示缓存资源未改动(Not Modified),资源会被重定向到浏览器缓存,这种情况下网络请求对应的状态码是 304
。
Last-Modified 和 If-Modified-Since
基于资源在服务器修改时间的验证缓存过期机制
当客户端再次请求该资源的时候,会在其请求头上附带上 If-Modified-Since
字段,值就是第一次获取请求资源时响应头中返回的 Last-Modified
值。如果资源未过期,命中缓存,服务器就直接返回 304
状态码,客户端直接使用本地的资源。否则,服务器重新发送响应资源。从而保证资源的有效性。
Etag 和 If-None-Match
基于服务资源校验码的验证缓存过期机制
服务器返回的报文响应头的 Etag
字段标示服务器资源的校验码(例如文件的 hash
值),发送到客户端浏览器,浏览器收到后把资源文件缓存起来并且缓存 Etag
值,当浏览器再次请求此资源文件时,会在请求头 If-None-Match
字段带上缓存的 Etag
值。
服务器收到请求后,把请求头中 If-None-Match
字段值与服务器端资源文件的验证码进行对比,如果匹配成功直接返回 304
状态码,从浏览器本地缓存取资源文件。如果不匹配,服务器会把新的验证码放在请求头的 etag
字段中,并且以 200
状态码返回资源。
需要注意的是当响应头中同时存在 Etag 和 Last-Modified 的时候,会先对 Etag 进行比对,随后才是 Last-Modified
参考
- 《图解 HTTP》
- 《计算机网络基础》
- https://blog.csdn.net/qzcsu/article/details/72861891
- https://segmentfault.com/a/1190000011145364
- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ
最后
如果你想进【大前端交流群】,关注公众号点击“交流加群”添加机器人自动拉你入群。关注我第一时间接收最新干货。
![](https://camo.githubusercontent.com/7c7e56fc99ebb78697a9b7c0cfa6264005000ece8778fbda12c1bdb5d5ccb7b7/68747470733a2f2f757365722d676f6c642d63646e2e786974752e696f2f323031392f352f31392f313661636661363030663932343034653f773d32303826683d32313026663d706e6726733d3336373636)