zoukankan      html  css  js  c++  java
  • 网络协议原理解析

    TCP 和 UDP 的区别

    概括:TCP是一个面向连接的、可靠的、基于字节流的传输层协议。

    • TCP是安全可靠的传输协议,提现出来一个是有状态,另一个是可控制。TCP 会精准记录哪些数据发送了,哪些数据被对方接收了,哪些没有被接收到,而且保证数据包按序到达,不允许半点差错。这是有状态。当意识到丢包了或者网络环境不佳,TCP 会根据具体情况调整自己的行为,控制自己的发送速度或者重发。这是可控制
    • 面向连接。所谓的连接,指的是客户端和服务器的连接,在双方互相通信之前,TCP 需要三次握手建立连接,而 UDP 没有相应建立连接的过程
    • 面向字节流。UDP 的数据传输是基于数据报的,这是因为仅仅只是继承了 IP 层的特性,而 TCP 为了维护状态,将一个个 IP 包变成了字节流
    • UDP 不止支持一对一的传输方式,同样支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能。

    TCP

    什么是三次握手?

    三次握手其实指的是三次信息交换过程,确认通信是否具备通信的能力(发送消息和接收消息),而且三次信息交换都需要加上编号

    从最开始双方都处于++CLOSED++状态。然后服务端开始监听某个端口,进入了++LISTEN++状态。
    然后客户端主动发起连接,发送 ++SYN++ , 自己变成了++SYN-SENT++状态。服务端接收到,返回++SYN++和++ACK++(对应客户端发来的SYN),自己变成了++SYN-REVD++。

    之后客户端再发送++ACK++给服务端,自己变成了++ESTABLISHED++状态;服务端收到++ACK++之后,也变成了++ESTABLISHED++状态。

    从图中可以看出: ++SYN++ 是需要消耗一个序列号的,下次发送对应的 ++ACK++ 序列号要加1

    为什么需要建立三次握手?

    如果我们假设一种场景,如果是建立二次握手,客户端在接受了 ++ACK+SYN++,建立好了连接。然后客户端接着断开了,这就带来了连接资源的浪费

    三次握手过程中可以携带数据么?

    第三次握手的时候,可以携带。前两次握手不能携带数据。

    如果前两次握手能够携带数据,那么一旦有人想攻击服务器,那么他只需要在第一次握手中的 SYN 报文中放大量数据,那么服务器势必会消耗更多的时间和内存空间去处理这些数据,增大了服务器被攻击的风险。

    第三次握手的时候,客户端已经处于++ESTABLISHED++状态,并且已经能够确认服务器的接收、发送能力正常,这个时候相对安全了,可以携带数据。

    如果服务端和客户端同时打开会怎样?

    1. 客户端发送 ++SYN++,服务端也发送 ++SYN++
    2. 客户端和服务端同时发送 ++SYN+ACK++
    3. 最后双方同时进入 ++ESTABLISHED++

    什么是四次挥手?

    第一次挥手:客户端发送FIN=1,用来关闭客户端到服务端的数据传送,随机产生一个seq=u,将该数据包发送给服务端,客户端进入FIN_WAIT_1状态。

    第二次挥手:服务端收到结束标志FIN=1后,发送确认标志ACK=1给客户端,确认号ack=u+1,随机产生一个seq=v,将该数据包发送给客户端,服务端进入CLOSE_WAIT状态,第二次挥手主要是告诉客户端收到了FIN 状态的数据包。

    第三次挥手:当服务器端发送完所有的请求后,服务端发送结束标志FIN=1,用来关闭服务端到客户端的数据传送,并发送确认标志ACK=1,随机产生一个seq=w,ack=u+1,将该数据包发送给客户端,服务端进入LAST_ACK状态。

    第四次挥手:客户端收到FIN后,客户端进入TIME_WAIT状态,接着发送确认标志ACK=1给服务端,确认号seq=u+1,服务端进入CLOSED状态。在这个过程中会等待2MSL(2个最长报文存活时间)
    完成四次挥手,成功断开连接。

    TCP四次挥手为什么要等待2MSL?

    1. 防止客户端最后一次发给服务器的确认在网络中丢失以至于客户端关闭,而服务端并未关闭,导致资源的浪费。
    2. 等待最大的2msl可以让本次连接的所有的网络包在链路上消失,以防造成不必要的干扰。

    如果client直接closed,然后又向server发起了一个新连接,我们不能保证这个新连接和刚关闭的连接的端口号是不同的。假设新连接和已经关闭的老端口号是一样的,如果前一次滞留的某些数据仍然在网络中,这些延迟数据会在新连接建立后到达Server,所以socket就认为那个延迟的数据是属于新连接的,数据包就会发生混淆。所以client要在TIME_WAIT状态等待2倍的MSL,这样保证本次连接的所有数据都从网络中消失。

    半连接队列和 SYN Flood 洪水攻击的关系

    三次握手前,服务端的状态从CLOSED变为LISTEN, 同时在内部创建了两个队列:半连接队列和全连接队列,即SYN队列和ACCEPT队列

    半连接队列

    当客户端发送++SYN++到 服务端端,服务器端发送 ++ACK+SYN++,状态由++LISTEN++进入到++SYN-REVD++,此时这个连接就被推入了SYN队列,也就是半连接队列

    全连接队列

    当客户端返回ACK, 服务端接收后,三次握手完成。这个时候连接等待被具体的应用取走,在被取走之前,它会被推入另外一个 TCP 维护的队列,也就是全连接队列(Accept Queue)

    SYN Flood 攻击原理

    SYN Flood 属于典型的 DoS/DDoS 攻击。其攻击的原理很简单,就是用客户端在短时间内伪造大量不存在的 IP 地址,并向服务端疯狂发送SYN。对于服务端而言,会产生两个危险的后果:

    • 处理大量的SYN包并返回对应ACK, 势必有大量连接处于SYN_RCVD状态,从而占满整个半连接队列,无法处理正常的请求。
    • 由于是不存在的 IP,服务端长时间收不到客户端的ACK,会导致服务端不断重发数据,直到耗尽服务端的资源。

    如何应对 SYN Flood 攻击?

    • 增加半连接队列容量
    • 减少SYN+ACK重复次数
    • 利用 SYN Cookie 技术,在服务端接收到SYN后不立即分配连接资源,而是根据这个SYN计算出一个Cookie,连同第二次握手回复给客户端,在客户端回复ACK的时候带上这个Cookie值,服务端验证 Cookie 合法之后才分配连接资源
    • Syn Cache技术,这种技术是在收到SYN数据报文时不急于去分配TCB,而是先回应一个SYN ACK报文,并在一个专用HASH表(Cache)中保存这种半开连接信息,直到收到正确的回应ACK报文再分配TCB。在FreeBSD系统中这种Cache每个半开连接只需使用160字节,远小于TCB所需的736个字节
    • 使用SYN Proxy防火墙,防火墙中都提供一种SYN代理的功能,其主要原理是对试图穿越的SYN请求进行验证后才放行

    TCP 的 keep-alive?

    TCP 的 keep-alive 用来探测对端的连接有没有失效

    TCP 报文头部的字段

    一个TCP连接都是四元组,由源IP、源端口、目标IP、目标端口唯一确定一个连接。其中源IP和目标IP在IP协议中处理

    序列号

    即Sequence number, 指的是本报文段第一个字节的序列号。

    从图中可以看出,序列号是一个长为 4 个字节,也就是 32 位的无符号整数,表示范围为 0 ~ 2^32 - 1。如果到达最大值了后就循环到0

    ISN(初始序列号)

    每 4s 加 1,溢出则回到 0,如果 ISN 被攻击者预测到,要知道源 IP 和源端口号都是很容易伪造的,当攻击者猜测 ISN 之后,直接伪造一个 RST 后,就可以强制连接关闭的,这是非常危险的

    RST 攻击

    A和服务器B之间建立了TCP连接,此时C伪造了一个TCP包发给B,使B异常的断开了与A之间的TCP连接,就是RST攻击了

    窗口大小

    占用两个字节,也就是 16 位,但实际上是不够用的。因此 TCP 引入了窗口缩放的选项,作为窗口缩放的比例因子,这个比例因子的范围在 0 ~ 14,比例因子可以将窗口的值扩大为原来的 2 ^ n 次方。

    校验和

    占用两个字节,防止传输过程中数据包有损坏,如果遇到校验和有差错的报文,TCP 直接丢弃之,等待重传。

    TCP流量控制和拥塞控制

    TCP 采用大小可控制的流量窗口来控制,发送窗口在连接建立时由双方商定。但在通信的过程中,接收方可根据自己的资源情况,随时动态地调整对方的发送窗口上限值

    • 接收端窗口 rwnd(也称为通知窗口):接收端缓冲区大小,表示接收方的接收能力。接收端将此窗口值放在 TCP 报文的首部中的窗口字段,传送给发送端。
    • 拥塞窗口cwnd (congestion window):发送端缓冲区大小
    • 发送窗口swnd:发送窗口的上限值 = Min [rwnd, cwnd]
    • 当 rwnd < cwnd 时,是接收端的接收能力限制发送窗口的最大值

    流量控制

    流量控制:就是让发送方的发送速率不要太快,让接收方来得及接收。

    拥塞

    拥塞是指:数据发送速度超出网络所能承受的极限,经常造成路由器丢包的现象

    慢启动(慢开始)

    刚开始的时候,不知道网络的情况,如果做的太激进,发包太急,那么疯狂丢包,造成雪崩式的网络灾难

    在每收到一个对新的报文段的确认后,将拥塞窗口增加至多一个 MSS(最大报文长度的值) 的数值(一开始窗口大小为1,发送一个,接收一个,增长为2;发送两个,得到两个确认,增长为4......因此,窗口是指数增长的)

    慢启动阈值

    因为拥塞窗口是指数增长的,为防止后期增长过快,需要另外一个变量---慢开始门限(阈值),它的阈值叫做慢启动阈值,到底阀值后,以前一个 RTT 下来,cwnd翻倍,现在cwnd只是增加 1 而已

    快速重传

    在 TCP 传输的过程中,如果发生了丢包,即接收端发现数据段不是按序到达的时候,接收端的处理是重复发送之前的 ACK,在收到发送端的报文后,接收端回复一个 ACK 报文,那么在这个报文首部的可选项中,就可以加上SACK这个属性,通过left edge和right edge告知发送端已经收到了哪些区间的数据报。因此,即使第 5 个包丢包了,当收到第 6、7 个包之后,接收端依然会告诉发送端,这两个包到了。剩下第 5 个包没到,就重传这个包。这个过程也叫做选择性重传(SACK,Selective Acknowledgment)

    快速恢复

    发送端收到三次重复 ACK 之后,发现丢包,觉得现在的网络已经有些拥塞了,自己会进入快速恢复阶段

    1. 拥塞阈值降低为 cwnd 的一半
    2. cwnd 的大小变为拥塞阈值
    3. cwnd 线性增加

    TCP之Nagle算法&&延迟ACK

    Nagle算法

    为了解决小分组的数量,从而减小网络拥塞的出现,其中小分组的定义是小于MSS(最大报文长度)的任何分组

    算法规则

    • 当第一次发送数据时不用等待,就算是 1byte 的小包也立即发送
    • 后面发送满足下面条件之一就可以发了:
    • 数据包大小达到最大段大小(Max Segment Size, 即 MSS)
    • 之前所有包的 ACK 都已接收到

    延迟ACK

    如果tcp对每个数据包都发送一个ack确认,那么只是一个单独的数据包为了发送一个ack代价比较高,所以tcp会延迟一段时间,如果这段时间内有数据发送到对端,则捎带发送ack,总结来说就是延迟合并发送ack。

    以下场景不适合延迟

    • 需要调整窗口大小
    • 乱序需要重发的时候

    如果同时使用Nagle和延迟ACK

    使用Nagle,两次写数据长度小于MSS,当第一次写数据到达对端后,对端延迟ack,不发送ack,而本端因为要发送的数据长度小于MSS,所以nagle算法起作用,数据并不会立即发送,而是等待对端发送的第一次数据确认ack;这样的情况下,需要等待对端超时发送ack,然后本段才能发送第二次写的数据,从而造成延迟,产生性能问题

    HTTP(超文本传输协议)

    HTTP 报文

    HTTP 状态码

    状态码 描述
    101 Switching Protocols(交换协议),切换到更高级的协议,例如WebSocket 通信
    200 请求成功。一般用于GET与POST请求
    201 已创建。成功请求并创建了新的资源
    204 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
    205 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
    206 部分内容。服务器成功处理了部分GET请求
    301 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
    302 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
    304 未修改,命中协商缓存。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
    401 请求要求用户的身份认证
    403 服务器理解请求客户端的请求,但是拒绝执行此请求
    404 服务器无法根据客户端的请求找到资源(网页)
    500 服务器内部错误,无法完成请求
    501 服务器不支持请求的功能,无法完成请求
    502 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应

    GET 和 POST 有什么区别?

    首先最直观的是语义上的区别。
    而后又有这样一些具体的差别:

    • 从缓存的角度,GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。
    • 从编码的角度,GET 只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制。
    • 从参数的角度,GET 一般放在 URL 中,因此不安全,POST 放在请求体中,更适合传输敏感信息。
    • 从幂等性的角度,GET是幂等的,而POST不是。(幂等表示执行相同的操作,结果也是相同的)
    • 从TCP的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)

    HTTPS 详解

    简介

    HTTPS 协议之所以是安全的是因为 HTTPS 协议会对传输的数据进行加密,而加密过程是使用了非对称加密实现。但其实,HTTPS 在内容传输的加密上使用的是对称加密,非对称加密只作用在证书验证阶段

    首先需要理解对称加密和非对称加密的概念,然后讨论两者应用后的效果如何。

    对称加密是最简单的方式,指的是加密和解密用的是同样的密钥。

    而对于非对称加密,如果有 A、 B 两把密钥,如果用 A 加密过的数据包只能用 B 解密,反之,如果用 B 加密过的数据包只能用 A 解密.

    对称加解密过程

    接着我们来谈谈浏览器和服务器进行协商加解密的过程。

    首先,浏览器会给服务器发送一个随机数 client_random 和一个加密的方法列表。

    服务器接收后给浏览器返回另一个随机数 server_random 和加密方法。

    现在,两者拥有三样相同的凭证: client_random、server_random 和加密方法。

    接着用这个加密方法将两个随机数混合起来生成密钥,这个密钥就是浏览器和服务端通信的暗号

    影响

    如果只是采用对称加密的方式,如果遇到中间人攻击,那么第三方可以在中间获取到client_random、server_random和加密方法,由于这个加密方法同时可以解密,那么第三方就可以很成功的拿到数据,对其进行加解密

    思考?

    是否可以采用非对称加密的方式进行加解密呢?实际上非对称加密需要的计算量非常大,对于稍微大一点的数据即使用最快的处理器也非常耗时,这样数据传输的时间大大加长,造成网络的阻塞

    是否需要证书?

    如果只是采用的非对称加密算法,黑客如果采用 DNS 劫持,将目标地址替换成黑客服务器的地址,然后黑客自己造一份公钥和私钥,照样能进行数据传输.

    为了获取这个证书,服务器运营者需要向第三方认证机构获取授权,这个第三方机构也叫CA(Certificate Authority), 认证通过后 CA 会给服务器颁发数字证书, 假设不存在认证机构,任何人都可以制作证书,这带来的安全风险便是经典的“中间人攻击”问题。

    HTTPS 是怎么做的呢?

    HTTPS 的整体过程分为证书验证和数据传输阶段

    证书验证阶段

    浏览器向服务器发送client_random和加密方法列表。

    服务器接收到,返回server_random、加密方法以及公钥。

    ++浏览器接收,接着生成另一个随机数pre_random, 并且通过证书中的公钥对随机数进行加密传输到服务端,传给服务器。++

    服务器用公钥解密这个被加密后的pre_random

    现在浏览器和服务器有三样相同的凭证:client_random、server_random和pre_random。然后两者用相同的加密方法混合这三个随机数,生成最终的密钥。

    CA证书认证过程

    首先会读取证书中的明文内容。CA 进行数字证书的签名时会保存一个 Hash 函数,来这个函数来计算明文内容得到信息A,然后用公钥解密明文内容得到信息B,两份信息做比对,一致则表示认证合法

    当然有时候对于浏览器而言,它不知道哪些 CA 是值得信任的,因此会继续对CA链进行查找,查找 CA 的上级 CA,以同样的信息比对方式验证上级 CA 的合法性。一般根级的 CA 会内置在操作系统当中,当然如果向上找没有找到根级的 CA,那么将被视为不合法

    数据传输阶段

    浏览器和服务器尽管用一样的密钥进行通信,即使用对称加密。

    结论

    回头比较一下和单纯的使用非对称加密, 这种方式做了什么改进呢?本质上是防止了私钥加密的数据外传。单独使用非对称加密,最大的漏洞在于服务器传数据给浏览器只能用私钥加密,这是危险产生的根源。利用对称和非对称加密结合的方式,就防止了这一点,从而保证了安全

    HTTPS 它在 HTTP 和 TCP 的传输中建立了一个 SSL 安全层,利用对称加密和非对称机密结合数字证书认证的方式,让传输过程的安全性大大提高

    HTTP1.O

    HTTP 1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求。但是,这也造成了一些性能上的缺陷

    HTTP 1.1

    在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。一个包含有许多图像的网页文件的多个请求和应答可以在一个连接中传输,但每个单独的网页文件的请求和应答仍然需要使用各自的连接

    HTTP1.1也扩充了请求头来改进和扩充1.1的功能.例如,HTTP 1.0不支持Host请求头字段,WEB浏览器无法使用主机头名来明确表示要访问服务器上的哪个WEB站点,这样就无法使用WEB服务器在同一个IP地址和端口号上配置多个虚拟WEB站点。可以设置Connection请求头的值为Keep-Alive时,客户端通知服务器返回本次请求结果后保持连接;Connection请求头的值为close时,客户端通知服务器返回本次请求结果后关闭连接。HTTP 1.1还提供了与身份认证、状态管理和Cache缓存等机制相关的请求头和响应头。HTTP/1.0不支持文件断点续传

    HTTP1.1 如何解决 HTTP 的队头阻塞问题?

    什么是 HTTP 队头阻塞?
    从前面的小节可以知道,HTTP 传输是基于请求-应答的模式进行的,报文必须是一发一收,但值得注意的是,里面的任务被放在一个任务队列中串行执行,一旦队首的请求处理太慢,就会阻塞后面请求的处理。这就是著名的HTTP队头阻塞问题。

    并发连接

    对于一个域名允许分配多个长连接,那么相当于增加了任务队列,不至于一个队伍的任务阻塞其它所有任务。在RFC2616规定过客户端最多并发 2 个连接,不过事实上在现在的浏览器标准中,这个上限要多很多,Chrome 中是 6 个

    域名分片

    一个域名不是可以并发 6 个长连接吗?那我就多分几个域名。
    比如 content1.sanyuan.com 、content2.sanyuan.com。
    这样一个sanyuan.com域名下可以分出非常多的二级域名,而它们都指向同样的一台服务器,能够并发的长连接数更多了,事实上也更好地解决了队头阻塞的问题。

    HTTP2.O

    在性能提升方面,添加了新的功能:

    • 头部压缩
    • 多路复用

    另外还有:

    • 设置请求优先级
    • 服务器推送

    头部压缩

    头部压缩主要采用了 HPACK 算法,在HTTP通信的过程中,每一次请求都会发送相同的头部,以及相同的键值信息,这个时候还是存在非常大的优化空间的

    Hpack算法

    HTTP1.x的header中的字段很多时候都是重复的,例如method:get、status:200等等,随着网页增长到需要数十到数百个请求,这些请求中的冗余标头字段不必要地消耗带宽,从而显著增加了延迟

    思想原理

    通信的双方各拥有一本字典,记录着某些字符对应的文本内容

    过程

    消息发送端和消息接受端共同维护一份静态表和一份动态表(这两个合起来充当字典的角色),
    每次请求时,发送方根据字典的内容以及一些特定指定编码压缩消息头部,
    接收方根据字典进行解码,并且根据指令来判断是否需要更新动态表

    静态表

    • name和value都可以完全确定,这种已知键值对的方式,直接用一个字符来表示
    • 只能够确定name:比如:authority、cookie,首先将name部分先用一个字符(比如cookie)来表示,同时,根据情况判断是否告知服务端,将 cookie: xxxxxxx 添加到动态表中(我们这里默认假定是从客户端向服务端发送消息)

    动态表

    动态表最初是一个空表,当每次解压头部的时候,有可能会添加条目(比如前面提到的cookie,当解压过一次cookie时,cookie: xxxxxxx就有可能被添加到动态表了,至于是否添加要根据后面提到的指令判断)
    动态表允许包含重复的条目,也就是可能出现完全相同的键值对
    为了限制解码器的需求,动态表大小有严格限制的

    索引地址空间

    静态表和动态表一起组成一个索引地址空间。设静态表长度为s,动态表长度为k,那么最终的索引空间如下

    • 索引1-s是静态表,s-s+k是动态表,
    • 新的条目从在动态表的开头插入,从动态表末尾移除
    • 字段的name使用索引值表示,字段的value直接使用原有字面的值的八位字节序列或者使用静态哈夫曼编码表示
    • 字符串编码过的数据,如果标志位H为"0",则编码数据是字符串文字的原始八位字节;如果H是"1",则编码数据是字符串文字的huffman编码,剩下7位表示数据长度Length,以及8位字节序列表示的原有字面字符串

    优势

    可以在传输的过程,简化消息内容,从而降低消息的大小

    头部压缩可以减小请求的头部大小
    二次压缩的压缩率会更高(压缩体积越减越小)

    多路复用

    而 HTTP/2 便从 HTTP 协议本身解决了队头阻塞问题。注意,这里并不是指的TCP队头阻塞,而是HTTP队头阻塞,两者并不是一回事。TCP 的队头阻塞是在数据包层面,单位是数据包,前一个报文没有收到便不会将后面收到的报文上传给 HTTP,而HTTP 的队头阻塞是在 HTTP 请求-响应层面,前一个请求没处理完,后面的请求就要阻塞住。两者所在的层次不一样。

    之前解决HTTP队头堵塞问题一般采用并发连接,或者是多域名的方式,这也会引发相互竞争资源的问题,而HTTP2从协议本身去解决这个问题。

    原来Headers + Body的报文格式如今被拆分成了一个个二进制的帧,用Headers帧存放头部字段,Data帧存放请求体数据。分帧之后,服务器看到的不再是一个个完整的 HTTP 请求报文,而是一堆乱序的二进制帧。这些二进制帧不存在先后关系,因此也就不会排队等待。

    服务器推送

    在 HTTP/2 当中,服务器已经不再是完全被动地接收请求,响应请求,它也能新建 stream 来给客户端发送消息,当 TCP 连接建立之后,比如浏览器请求一个 HTML 文件,服务器就可以在返回 HTML 的基础上,将 HTML 中引用到的其他资源文件一起返回给客户端,减少客户端的等待。

    前端缓存到底是什么?

    强缓存

    浏览器中的缓存作用分为两种情况,一种是需要发送HTTP请求,一种是不需要发送。

    首先是检查强缓存,这个阶段不需要发送HTTP请求。

    如何来检查呢?通过相应的字段来进行,但是说起这个字段就有点门道了。

    在HTTP/1.0和HTTP/1.1当中,这个字段是不一样的。在早期,也就是HTTP/1.0时期,使用的是Expires,而HTTP/1.1使用的是Cache-Control。让我们首先来看看Expires:

    Expires:Thu,31 Dec 2037 23:59:59 GMT。这个时间代表着这个资源的失效时间,也就是说在2037年12月31日23点59分59秒之前都是有效的,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,用这个时间和客户端比较来判断是否过期失效,所以当客户端本地时间被修改以后,服务器与客户端时间偏差变大以后,就会导致缓存混乱

    Cache-Control:Cache-Control使用的是相对时间, Cache-Control:max-age=31536000,也就是说缓存有效期为(31536000 / 24 / 60 * 60)天,过了这个时间就会失效,相当于是一个倒计时的过程。

    禁用缓存并且没有超过有效时间的情况下,再次访问这个资源就命中了缓存,不会向服务器请求资源而是直接从浏览器缓存中取。

    • s-maxage 同 max-age,覆盖 max-age、Expires,但仅适用于共享缓存,在私有缓存中被忽略。
    • public 表明响应可以被任何对象(发送请求的客户端、代理服务器等等)缓存。
    • private 表明响应只能被单个用户(可能是操作系统用户、浏览器用户)缓存,是非共享的,不能被代理服务器缓存。
    • no-cache 强制所有缓存了该响应的用户,在使用已缓存的数据前,发送带验证器的请求到服务器,相当于是走协商缓存。
    • no-store 禁止缓存,每次请求都要向服务器重新获取数据。

    协商缓存

    如果没有命中强制缓存,发送http请求到服务器,服务器根据http头信息中的Last-Modify/If-Modify-Since或Etag/If-None-Match来判断是否命中协商缓存

    当浏览器再次请求该资源时,发送的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存,同样的,当浏览器再次请求该资源时,发送的请求头中会也包含If-None-Match,该值为缓存之前返回的Etag。服务器收到If-None-Match后,根据资源的ETag值是否发生变化来判断是否命中缓存。

    Etag 的生成

    • 文件的i-node编号,此i-node非彼iNode。是Linux/Unix用来识别文件的编号
    • 文件最后修改时间
    • 文件大小

    Etag 是通过上面的因子,使用抗碰撞散列函数来生成,理论上ETag也是会重复的,只是概率小到可以忽略。

    Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304

    为什么 Etag 会优于 Last-Modified?

    • 在精准度上,ETag优于Last-Modified。优于 ETag 是按照内容给资源上标识,因此能准确感知资源的变化。而 Last-Modified 就不一样了,它在一些特殊的情况并不能准确感知资源变化,主要有两种情况:
    • 编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。
    • Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了

    Memory Cache 和 Disk Cache

    我们可以看到,在命中强制缓存的情况下,状态码是200,但会从内存中,或者是从本地磁盘中读取。

    Memory Cache指的是内存缓存,从效率上讲它是最快的。但是从存活时间来讲又是最短的,当渲染进程结束后,内存缓存也就不存在了。

    Disk Cache就是存储在磁盘中的缓存,从存取效率上讲是比内存缓存慢的,但是他的优势在于存储容量和存储时长。

    读取规则涉及到三级缓存原理

    1. 先查找内存,如果内存中存在,从内存中加载;
    2. 如果内存中未查找到,选择硬盘获取,如果硬盘中有,从硬盘中加载;
    3. 如果硬盘中未查找到,那就进行网络请求;
    4. 加载到的资源缓存到硬盘和内存;

    存放的规则根据LRU(最近最少使用)的方法帮经常使用的资源存在内存中,不经常使用的存在磁盘中,当达到存储的阀值,定期清除磁盘中的资源

    HTTP2 push cache

    详细内容查看 : 阅读理解:HTTP/2 push is tougher than I thought

  • 相关阅读:
    第三周学习进度条
    绘制echarts折线图
    第二周学习进度条
    返回一个整数数组中最大子数组的和
    软件工程第二周开课博客
    第一周学习进度条
    学习进度
    学习进度
    学习进度
    HDU 4906 (dp胡乱搞)
  • 原文地址:https://www.cnblogs.com/fuGuy/p/13089548.html
Copyright © 2011-2022 走看看