网络通信_知识点精讲

当我们面对失败的时候,最让我们难以接受的,不是挫败感,而是大众的否定和轻视

大家好,我是柒八九

今天,我们继续前端面试的知识点。我们来谈谈关于网络通信的相关知识点和具体的算法。

该系列的文章,大部分都是前面文章的知识点汇总,如果想具体了解相关内容,请移步相关系列,进行探讨。

如果,想了解该系列的文章,可以参考我们已经发布的文章。如下是往期文章。

文章list

  1. CSS重点概念精讲
  2. JS_基础知识点精讲

好了,天不早了,干点正事哇。

The flow of network packets

大致经历了5个组件或者步骤:

  1. 客户端 - 一般为浏览器
    1. 浏览器
    2. Socket库
    3. TCP协议栈
    4. IP协议栈
    5. 网卡驱动
    6. 网卡
  2. 客户端局域网
    1. 双绞线
    2. 集线器
    3. 交换机 (MAC地址)
    4. 路由器 (IP地址)
    5. ADSL Modem => ATM信元 => 电信号
  3. 接入网
  4. Web服务器局域网
    1. 防火墙
    2. 缓存服务器
  5. Web服务器

TCP/IP 网络模型

通信模型

五层模型

四层模型

把链路层和物理层都表示为网络接口层

OSI 七层网络模型

在五层协议之上加了表示层和会话层


生成HTTP消息

URL

URL{统一资源定位符|Uniform Resource Locator},是互联网上标准资源的地址。

互联网上的每个文件都有唯一的一个的URL

  • 它包含的信息指出文件的位置
  • 以及浏览器应该怎么处理它

基本URL包含:模式(或称协议)、服务器名称(或IP地址/网址)、路径和文件名。

  • 其一般语法格式为:protocol :// hostname[:port] / path / [;parameters][?query]#fragment

浏览器是一个具备多种客户端功能综合性客户端软件


浏览器解析URL

浏览器要做的第一步工作就是对 URL 进行解析,从而生成发送给 Web服务器的请求消息

解析过程


HTTP 的基本思路

HTTP 的基本思路

HTTP 协议定义了客户端和服务器之间交互的消息内容和步骤

客户端向服务器发送请求消息

请求消息中包含的内容是对什么进行怎样的操作两个部分

1. 对什么 (URI)

其中相当于“对什么”的部分称为 URI。一般来说,URI 的内容是一个存放网页数据的文件名,例如/dir1/file1.html

URI:{统一资源标识符|Uniform Resource Identifier}

2. 进行怎样的操作 (方法)

把“进行怎样的操作”的部分称为方法

GETPOST 比较


生成HTTP请求消息

对 URL 进行解析之后,浏览器确定了 Web 服务器文件名,接下来就是根据这些信息来生成 HTTP 请求消息了。

请求消息格式

  1. 请求行
    • 请求消息的第一行称为请求行。
    • <方法> <URI> <HTTP版本>
    • 重点是最开头方法,方法可以告诉 Web 服务器它应该进行怎样的操作
      • 方法有很多种,我们必须先判断应该选用其中的哪一种。解决这个问题的关键在于浏览器的工作状态
    • URI 部分的格式如下,一般是文件和程序的路径名
      • /< 目录名 >/…/< 文件名 >
    • 第一行的末尾需要写上 HTTP 的版本号,这是为了表示该消息是基于哪个版本的 HTTP 规格编写的。到此为止,第一行就结束了
  2. 消息头
    • 有些情况下还需要一些额外的详细信息,而消息头的功能就是用来存放这些信息的。
    • 消息头按照用途可分为四大类
      1. 通用头:适用于请求和响应的头字段
      2. 请求头:用于表示请求消息的附加信息的头字段
      3. 响应头:用于表示响应消息的附加信息的头字段
      4. 实体头:用于消息体的附加信息的头字段
  3. 消息体
    • 写完消息头之后,还需要添加一个完全没有内容的空行
    • 然后写上需要发送的数据。这一部分称为消息体,也就是消息的主体。

发送请求后会收到响应

响应消息格式

在响应消息中,第一行的内容为状态码响应短语,用来表示请求的执行结果是成功还是出错。

  • 状态码是一个数字,它主要用来向程序告知执行的结果。
    • 状态码的第一位数字表示状态类型,第二、三位数字表示具体的情况
  • 响应短语则是一段文字,用来向人们告知执行的结果。

返回响应消息之后,浏览器会将数据类型 (Content-Type)提取出来并显示在屏幕上。


IP地址

客户端(浏览器)生成 HTTP 消息之后,接下来需要委托操作系统将消息发送给 Web 服务器。在委托操作系统发送消息时,必须要提供的不是通信对象的域名,而是它的 IP 地址

IP 地址是一个网卡在网络世界的通讯地址,相当于我们现实世界的门牌号码

MAC 地址

MAC 地址,是一个网卡的物理地址,用十六进制,6 个 byte 表示。

MAC 地址全局唯一,不会有两个网卡有相同的 MAC 地址,而且网卡自生产出来,就带着这个地址。

很多人看到这里就会想,只要知道了对方的 MAC 地址,就可以把信息传过去。这是行不通的。一个网络包要从一个地方传到另一个地方,除了要有确定的地址,还需要有定位功能。 而有门牌号码属性的 IP 地址,才是有远程定位功能的。

MAC 地址更像是身份证,是一个唯一的标识。它的唯一性设计是为了组网的时候,不同的网卡放在一个网络里面的时候,可以不用担心冲突。从硬件角度,保证不同的网卡有不同的标识

MAC 地址是有一定定位功能的,只不过范围非常有限。MAC 地址的通信范围比较小,局限在一个子网里面

动态主机配置协议(DHCP)

只要是在网络上跑的包,都是完整的,可以有下层没上层绝对不可能有上层没下层

假设,我们想要在源 IP 地址为 16.158.23.6 的机器上访问目标 IP 地址 为 192.168.1.6机器的数据。发现包发不出去,这是因为 MAC 层还没填。

  • Linux 首先会判断,要去的这个地址和我是一个网段的吗,或者和我的一个网卡是同一网段的吗

    • 只有是一个网段的,它才会发送 ARP 请求,获取 MAC 地址。
  • 如果发现不是

    • Linux 默认的逻辑是,如果这是一个跨网段的调用,它便不会直接将包发送到网络上,而是企图将包发送到网关
  • 如果你配置了网关的话,Linux 会获取网关的 MAC 地址,然后将包发出去。

手动配置需要不停的对自己机器的IP进行配置。是一件很麻烦的事。

需要有一个自动配置的协议,也就是称{动态主机配置协议|Dynamic Host Configuration Protocol},简称DHCP。

只需要配置一段共享的 IP 地址。每一台新接入的机器都通过 DHCP 协议,来这个共享的 IP 地址里申请,然后自动配置好就可以了。等人走了,或者用完了,还回去,这样其他的机器也能用。


DNS协议:网络世界的地址簿

Socket 库提供查询 IP 地址的功能

向 DNS 服务器发出查询,并接收服务器返回的响应消息。对于 DNS 服务器,我们的计算机上一定有相应的 DNS 客户端,而相当于 DNS 客户端的部分称为 DNS 解析器,或者简称解析器

通过 DNS 查询 IP 地址的操作称为域名解析

解析器实际上是一段程序,它包含在操作系统的 Socket 库中。

解析器向 DNS 服务器发出查询

解析器的调用方法

调用解析器后,解析器会向 DNS 服务器发送查询消息,然后 DNS 服务器会返回响应消息。响应消息中包含查询到的 IP 地址,解析器会取出 IP 地址,并将其写入浏览器指定内存地址中。

接下来,浏览器在向 Web 服务器发送消息时,只要从该内存地址取出 IP 地址,并将它与 HTTP 请求消息一起交给操作系统就可以了。

在 Socket 库中,采用 UDP 协议,进行信息的查询。

DNS 服务器的工作步骤

DNS 服务器的基本工作就是接收来自客户端的查询消息,然后根据消息的内容返回响应

来自客户端的查询消息包含以下 3 种信息

类型 描述
域名 服务器、邮件服务器(邮件地址中 @ 后面的部分)的名称
Class Class 的值永远是代表互联网的 IN
记录类型 表示域名对应何种类型的记录

类型为 A 时:表示域名对应的是 IP 地址
类型为 MX 时:表示域名对应的是邮件服务器

A 是 Address 的缩写 /MX:Mail eXchange,邮件交换的缩写

DNS 服务器上事先保存有前面这 3 种信息对应的记录数据。

DNS 服务器的基本工作

例如,如果要查询 www.wl.com 这个域名对应的 IP 地址,客 户端会向 DNS 服务器发送包含以下信息的查询消息。

信息
域名 = www.wl.com
Class = IN
记录类型 = A

然后,DNS 服务器会从已有的记录中查找域名、Class 和记录类型全部匹配的记录。

DNS 服务器会从域名与 IP 地址的对照表中查找相应的记录,并返回 IP 地址

实际上还有很多其他的类型。

  • 根据 IP 地址反查域名PTR 类型
  • 查询域名相关别名CNAME类型
  • 查询 DNS 服务器 IP 地址的 NS 类型
  • 以及查询域名属性信息SOA 类型等

信息是如何在 DNS 服务器上注册

首先,DNS 服务器中的所有信息都是按照域名以分层次的结构来保存的。DNS 中的域名都是用句点来分隔的,比如 www.wl.com,这里的句点代表了不同层次之间的界限。

在域名中,越靠右的位置表示其层级越高

这种具有层次结构的域名信息会注册到 DNS 服务器中,而每个域都是作为一个整体来处理的。

于是,DNS 服务器也具有了像域名一样的层次结构,每个域的信息都存放在相应层级的 DNS 服务器中。


寻找相应的 DNS 服务器并获取 IP 地址

这里的关键在于如何找到我们要访问的 Web 服务器的信息归哪一台 DNS 服务器管

comcn 这些域(称为顶级域),它们各自负责保存下级 DNS 服务器的信息。在互联网中,comcn 的上面还有一级域,称为根域。根域不像 com、cn 那样有自己的名字,因此在一般书写域名时经常被省略,如果要明确表示根域,应该像 www.wl.com. 这样在域名的最后再加上一个句点,而这个最后的句点就代表根域。

树状的层次结构

根域的 DNS 服务器中保管着 comcn 等的 DNS 服务器的信息

除此之外还需要完成另一项工作,那就是将根域的 DNS 服务器信息保存在互联网中所有的 DNS 服务器中。客户端只要能够找到任意一台DNS 服务器,就可以通过它找到根域 DNS 服务器,然后再一路顺藤摸瓜找到位于下层的某台目标 DNS 服务器。

分配给根域 DNS 服务器的 IP 地址在全世界仅有 13 个 ,而且这些地址几乎不发生变化。

DNS 解析流程

  1. 电脑客户端会发出一个 DNS 请求,问 www.wl.com 的 IP 是啥啊,并发给本地域名服务器 (本地 DNS)。

  2. 本地 DNS 收到来自客户端的请求。然后,查找对应的记录信息。

    • 如果能找到 www.wl.com,它直接就返回 IP 地址。
    • 如果没有,本地 DNS 会去问它的根域名服务器
  3. 根 DNS 收到来自本地 DNS 的请求,发现后缀是 .com,说:“www.wl.com 啊,这个域名是由.com 区域管理,我给你它的顶级域名服务器的地址,你去问问它吧。”

  4. 本地 DNS 转向问顶级域名服务器

    • 顶级域名服务器就是大名鼎鼎的比如 .com、.net、 .org 这些一级域名
    • 负责管理二级域名,比如 wl.com,所以它能提供一条更清晰的方向
  5. 顶级域名服务器说:“我给你负责 www.wl.com 区域的权威 DNS 服务器的地址,你去问它应该能问到。”

  6. 本地 DNS 转向问权威 DNS 服务器:“www.wl.com 对应的 IP 是啥呀?”

    • wl.com 的权威 DNS 服务器,它是域名解析结果的原出处。
    • 为啥叫权威呢?就是我的域名我做主。
  7. 权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。

  8. 本地 DNS 再将 IP 地址返回客户端客户端和目标建立连接

通过缓存加快 DNS 服务器的响应

如果要查询的域名和相关信息已经在缓存中,那么就可以直接返回响应,接下来的查询可以从缓存的位置开始向下进行。相比每次都从根域找起来说,缓存可以减少查询所需的时间。

这个缓存机制中有一点需要注意,那就是信息被缓存后,原本的注册信息可能会发生改变,这时缓存中的信息就有可能是不正确的。因此,DNS 服务器中保存的信息都设置有一个有效期,当缓存中的信息超过有效期后,数据就会从缓存中删除


负载均衡

内部负载均衡

例如,某个应用要访问另外一个应用,如果配置另外一个应用的 IP 地址,那么这个访问就是一对一的。但是当被访问的应用撑不住的时候,我们其实可以部署多个。但是,访问它的应用,如何在多个之间进行负载均衡?只要配置成为域名就可以了。在域名解析的时候,我们只要配置策略,这次返回第一个 IP,下次返回第二个 IP,就可以实现负载均衡了。

全局负载均衡

为了保证我们的应用高可用,往往会部署在多个机房每个地方都会有自己的 IP 地址。当用户访问某个域名的时候,这个 IP 地址可以轮询访问多个数据中心。如果一个数据中心因为某种原因挂了,只要在 DNS 服务器里面,将这个数据中心对应的 IP 地址删除,就可以实现一定的高可用。


HTTP 请求消息交给协议栈

协议栈并不关心应用程序传来的数据是什么内容,在协议栈看来,要发送的数据就是一定长度的二进制字节序列而已。

协议栈并不是一收到数据就马上发送出去,而是会将数据存放在内部的发送缓冲区中,并等待应用程序的下一段数据。

至于要积累多少数据才能发送,不能一概而论,但都是根据下面几个要素来判断的。

  1. 第一个判断要素是每个网络包能容纳的数据长度,协议栈会根据一个叫作{最大传输单元|Maximum Transmission Unit}(MTU)的参数来进行判断。

    • MTU 表示一个网络包的最大长度,在以太网中一般是 1500 字节。
    • MTU 是包含头部的总长度,因此需要从 MTU 减去头部的长度,然后得到的长度就是一个网络包中所能容纳的最大数据长度,这一长度叫作 {最大分段大小|Maximum Segment Size}(MSS)。
    • 当从应用程序收到的数据长度超过或者接近 MSS 时再发送出去,就可以避免发送大量小包的问题了。
    • MTU 与 MSS
  2. 另一个判断要素是时间

    • 当应用程序发送数据的频率不高的时候,如果每次都等到长度接近 MSS 时再发送,可能会因为等待时间太长而造成发送延迟,这种情况下,即便缓冲区中的数据长度没有达到 MSS,也应该果断发送出去。

较大的数据进行拆分

HTTP 请求消息一般不会很长,一个网络包就能装得下,但如果其中要提交表单数据,长度就可能超过一个网络包所能容纳的数据量。

这种情况下,发送缓冲区中的数据就会超过 MSS 的长度,这时我们当然不需要继续等待后面的数据了。发送缓冲区中的数据会被以 MSS 长度为单位进行拆分,拆分出来的每块数据会被放进单独的网络包中。

根据发送缓冲区中的数据拆分的情况,当判断需要发送这些数据时,就在每一块数据前面加上 TCP 头部,并根据套接字中记录的控制信息标记发送方和接收方的端口号,然后交给 IP 模块来执行发送数据的操作。

序数据的拆分

自此,从客户端发送的消息,被封装成一个个网络包。然后,就会顺着通信通道进行传输。


TCP

三次握手

TCP 头部信息

我们来简单介绍一下,重要字段的作用。

  • {源端口号|Source Port}/ {目标端口号|Destination Port}:
    • 用于区别主机中的不同进程
    • IP地址是用来区分不同的主机
    • 源端口号和目的端口号配合上IP首部中的源IP地址和目的IP地址就能唯一的确定一个TCP连接;
  • {分包序号|Sequence Number}:
    • 应用程序数据如果 大于 {最大分段大小|Maximum Segment Size}(MSS)就得要进行分段。
    • 这个 Sequence Number 就是记录每个封包的序号,可以让 server 重新将 TCP 的数据组合起来。
    • 主要用来解决网络报乱序的问题

  • {回应序号|Acknowledge Number}:
    • 为了确认发送端确实有收到接收端所送出的封包数据。
    • 接收端收到这个确认码时,就能够确定之前传递的封包已经被正确的收下了。
    • 回应序号应当是上次已成功收到分包序号加1
    • 用来解决不丢包的问题

  • Code{控制标识码|Control Flag}
    这个字段共有 6 个 bits ,分别代表 6 个句柄,若为 1 则为启动 (只介绍常用的)
    • SYN:若为 1,表示 client 希望双方建立同步处理
    • ACK:若为 1 代表这个封包为响应封包
    • FIN:若为 1 ,表示传送结束,所以通知对方数据传毕, 是否同意断线,只是发送者还在等待对方的响应而已

三次握手

  1. SYN
    • 客户端选择一个随机序列号 x,并发送一个 SYN 分组
  2. SYN + ACK
    • 服务器给 x 加 1
      • x + 1
    • 并选择自己的一个随机序列号
      • y
    • 然后返回响应
  3. ACK
    • 客户端给 x 和 y 加 1
      • x + 1
      • y + 1
    • 并发送握手期间的最后一个 ACK 分组

三次握手完成后,客户端与服务器之间就可以通信了。客户端可以在发送 ACK 分组之后立即发送数据,而服务器必须等接收到 ACK 分组之后才能发送数据。


滑动窗口

TCP 采用滑动窗口来管理数据发送和 ACK 号的操作。

所谓滑动窗口,就是在发送一个包之后,不等待 ACK 号返回,而是直接发送后续的一系列包

通过这种方式,就可以实现同一时间发送多个包,减少网络延迟。

其实,通过窗口,TCP 可以控制双向发送数据的速度

流量控制

流量控制是一种预防发送端过多向接收端发送数据的机制。

为实现流量控制,TCP 连接的每一方都要通告自己的接收窗口rwnd),其中包含能够保存数据的缓冲区空间大小信息

第一次建立连接时,两端都会使用自身系统的默认设置来发送 rwnd。在后面的数据交换过程中,每个 ACK 分组都会携带相应的最新 rwnd,以便两端动态调整数据流速,使之适应发送端和接收端的容量及处理能力。

慢启动 (利用可用宽带)

流量控制确实可以防止发送端向接收端过多发送数据,但却没有机制预防任何一端向潜在网络过多发送数据。换句话说,发送端和接收端在连接建立之初,谁也不知道可用带宽是多少。因此需要一个估算机制,然后还要根据网络中不断变化的条件而动态改变速度

拥塞窗口大小cwnd):发送端对从客户端接收确认(ACK)之前可以发送数据量的限制。发送端不会通告 cwnd 变量,即发送端和接收端不会交换这个值

服务器和客户端怎么确定拥塞窗口大小的最优值呢:解决方案就是慢启动:即在分组被确认后增大窗口大小,慢慢地启动

无论带宽多大,每个 TCP 连接都必须经过慢启动阶段

换句话说,应用不可能一上来就完全利用连接的最大带宽

初始拥塞窗口大小增加到一个合理值,可以减少客户端与服务器之间的往返时间


TCP队首阻塞

TCP 在不可靠的信道上实现了可靠的网络传输

每个 TCP 分组都会带着一个唯一的序列号被发出,而所有分组必须按顺序传送到接收端。如果中途有一个分组没能到达接收端,那么后续分组必须保存在接收端的 TCP 缓冲区,等待丢失的分组重发并到达接收端。这一切都发生在 TCP 层,应用程序对 TCP 重发和缓冲区中排队的分组一无所知,必须等待分组全部到达才能访问数据。在此之前,应用程序只能在通过套接字读数据时感觉到延迟交付。这种效应称为TCP {队首阻塞|Head of Line Blocking} (HOL)

TCP 队首阻塞

队首阻塞造成的延迟可以让我们的应用程序不用关心分组重排和重组,分组到达时间会存在无法预知的延迟变化。这个时间变化通常被称为抖动,也是影响应用程序性能的一个主要因素。

TCP 队首阻塞造成的延迟,也是影响应用程序性能的一个主要因素


四次挥手

  1. FIN
    • 客户端选择一个随机序列号 x,并发送一个 FIN 分组
  2. ACK
    • 服务器给 x 加 1
      • x + 1
  3. 等后端数据都传输完毕后。。。。。
  4. FIN
    • 服务器选择自己的一个随机序列号
      • y
  5. ACK
    • 客户端给 x 和 y 加 1
      • x + 1
      • y + 1
    • 并发送握手期间的最后一个 ACK 分组

注意点:

  1. 相比三次握手,四次挥手,在 server 发起的时候,是将控制标志码SYN 换成 FIN
  2. 可以看到,在第二次挥手和第三次挥手中间,有很多未发送完成的数据,其实也好理解,在 client 接收到 server 传入的 FIN 包时候,此时可能正处于某些大包数据的发送阶段,如果此时直接回复 发送端的断开操作。并且,如果 server FIN 包早于其他正常数据包到达 client。那这些本应该被 client 收录的数据,就会平白无故的丢失

为什么要四次挥手

TCP协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。

TCP是全双工模式,这就意味着

  • 当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据
  • 当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的
  • 当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接

HTTP缓存

缓存:何时起作用

HTTP缓存是作用于网站导航阶段的网络请求的开始阶段

  • SericeWorker之后
  • Socket 进行 DNS 查询之前

缓存的常见淘汰机制

在缓存中,存在两种比较常见的淘汰机制

  1. LRU:Least Recently Used->最近最少使用
    • 最近使用的数据是有用的,很久没使用过的数据是无用的,
    • 内存满了,先删除那些很久没用过的数据
  2. LFU:Least Frequently Used
    • 每次淘汰那些使用次数最少的数据

HTTP缓存策略

最好最快的请求就是没有请求

浏览器对静态资源的缓存本质上是 HTTP 协议的缓存策略,其中又可以分为

  1. 强制缓存
    • 根据过期时间决定使用本地缓存还是请求新资源
  2. 协商缓存
    • 每次都会发出请求,经过服务器进行对比后决定采用本地缓存还是新资源

两种缓存策略都会将资源缓存到本地

具体采用哪种缓存策略,由 HTTP 协议的首部( Headers )信息决定。

我们对HTTP缓存用到的字段进行一次简单的分类和汇总。

头字段 所属分组
Expires 实体头
Cache-control 通用头
ETag 实体头

ETag:

  • 更新操作中,有时候需要基于上一次请求的响应数据来发送下一次请求。
  • 在这种情况下,这个字段可以用来提供上次响应与下次请求之间的关联信息
  • 上次响应中,服务器会通过 Etag 向客户端发送一个唯一标识,在下次请求中客户端可以通过 If-MatchIf-None-MatchIf-Range 字段将这个标识告知服务器,这样服务器就知道该请求和上次的响应是相关的。

    这个字段的功能和 Cookie 是相同的,但 Cookie 是网景(Netscape)公司自行开发的规格,而 Etag 是将其进行标准化后的规格

Expires 和 Cache-control:max-age=x(强缓存)

ExpiresCache-control:max-age=x强制缓存策略的关键信息,两者均是响应首部信息(后端返给客户端)的。

ExpiresHTTP 1.0 加入的特性,通过指定一个明确的时间点作为缓存资源的过期时间,在此时间点之前客户端将使用本地缓存的文件应答请求,而不会向服务器发出实体请求。

Expires 的优点:

  • 可以在缓存过期时间内减少客户端的 HTTP 请求
  • 节省了客户端处理时间和提高了 Web 应用的执行速度
  • 减少了服务器负载以及客户端网络资源的消耗

对应的语法

Expires: Wed, 24 Oct 2022 14:00:00 GMT
复制代码

上述信息指定对应资源的缓存过期时间2022年8月24日 14点

Expires 一个致命的缺陷是:

  • 它所指定的时间点是以服务器为准的时间
  • 但是客户端进行过期判断时是将本地的时间与此时间点对比

如果客户端的时间与服务器存在误差,那么通过 Expires 控制的缓存资源将会失效,客户端将会发送实体请求获取对应资源。

针对这个问题, HTTP 1.1 新增了 Cache-control 首部信息以便更精准地控制缓存。

常用的 Cache-control 信息有以下几种。

  • no-cache:
    • no-cache将会和服务器进行一次通讯
  • no-store
    • no-store要求资源每次都被请求并且下载下来
  • public & private
    • public表示此响应可以被浏览器以及中间缓存器无限期缓存
    • private表示此响应可以被用户浏览器缓存,但是不允许任何中间缓存器对其进行缓存。
  • max-age=<seconds>
    • 指定从请求的时刻开始计算,此响应的缓存副本有效的最长时间(单位:
    • 例如,max-age=360表示浏览器在接下来的 1 小时内使用此响应的本地缓存,不会发送实体请求到服务器
  • no-transform
    • 中间代理有时会改变图片以及文件的格式,从而达到提高性能的效果。
    • no-transform指令告诉中间代理不要改变资源的格式

max-age 指定的是缓存的时间跨度,而非缓存失效的时间点,不会受到客户端与服务器时间误差的影响。

Expires 相比, max-age 可以更精确地控制缓存,并且比 Expires更高的优先级

强制缓存策略下( Cache-control 未指定 no-cacheno-store)的缓存判断流程


EtagIf-None-Match (协商缓存)

Etag服务器为资源分配的字符串形式唯一性标识,作为响应首部信息返回给浏览器

浏览器

  1. Cache-control 指定 no-cache
  2. 或者 max-ageExpires 均过期之后,

Etag 值通过 If-None-Match 作为请求首部信息发送给服务器。

服务器接收到请求之后,对比所请求资源的 Etag 值是否改变,

  • 如果未改变将返回 304 Not Modified,并且根据既定的缓存策略分配新的 Cache-control 信息;
  • 如果资源发生了改变,则会返回最新的资源以及重新分配Etag值。
  • ![](files.mdnice.com/user/24720/… =60%x)

如果强制浏览器使用协商缓存策略,需要将 Cache-control 首部信息设置为 no-cache ,这样便不会判断 max-ageExpires 过期时间,从而每次资源请求都会经过服务器对比


HTTP X.X

HTTP/0.9

HTTP/0.9 是于 1991 年提出的,主要用于学术交流,需求很简单——用来在网络之间传递 HTML 超文本的内容,所以被称为超文本传输协议

HTTP/0.9 的一个完整的请求流程

  • 因为 HTTP 都是基于 TCP 协议的,所以客户端先要根据 IP 地址、端口和服务器建立 TCP 连接,而建立连接的过程就是 TCP 协议三次握手的过程。
  • 建立好连接之后,会发送一个 GET 请求行的信息,如GET /index.html用来获取 index.html。
  • 服务器接收请求信息之后,读取对应的 HTML 文件,并将数据以 ASCII 字符流返回给客户端。
  • HTML 文档传输完成后,断开连接。

总的来说,当时的需求很简单,就是用来传输体积很小的 HTML 文件,所以 HTTP/0.9 的实现有以下三个特点。

  • 第一个是只有一个请求行,并没有 HTTP 请求头和请求体,因为只需要一个请求行就可以完整表达客户端的需求了。
  • 第二个是服务器也没有返回头信息,这是因为服务器端并不需要告诉客户端太多信息,只需要返回数据就可以了。
  • 第三个是返回的文件内容是以 ASCII 字符流来传输的,因为都是 HTML 格式的文件,所以使用 ASCII 字节码来传输是最合适的。

HTTP 1.0

HTTP 1.0 是在 1996 年引入的,由于在浏览器中展示的不单是 HTML 文件了,还包括了 JavaScriptCSS、图片、音频、视频等不同类型的文件。因此支持多种类型的文件下载是 HTTP/1.0 的一个核心诉求

  • HTTP 1.0 仅仅提供了最基本的认证,这时候用户名和密码还未经加密,因此很容易收到窥探。
  • HTTP/1.0 引入了请求头响应头,它们都是以为 Key-Value 形式保存的
  • HTTP 1.0 被设计用来使用短链接
    • 即每次发送数据都会经过 TCP 的三次握手和四次挥手,效率比较低。
  • HTTP 1.0 只使用 header 中的 If-Modified-SinceExpires 作为缓存失效的标准。
  • HTTP 1.0 不支持断点续传,也就是说,每次都会传送全部的页面和数据。

HTTP 1.1

HTTP 1.1 是 HTTP 1.0 开发三年后出现的,也就是 1999 年,它做出了以下方面的变化

  • HTTP 1.1 使用了摘要算法来进行身份验证
  • HTTP 1.1 默认使用长连接(持久连接)
    • 长连接就是只需一次建立就可以传输多次数据,传输完成后,只需要一次切断连接即可。
    • 长连接的连接时长可以通过请求头中的 keep-alive 来设置
    • 持久连接在 HTTP/1.1 中是默认开启
  • HTTP 1.1 中新增加了 E-tag, If-Match, If-None-Match 等缓存控制标头来控制缓存失效。
  • HTTP 1.1 支持断点续传,通过使用请求头中的 Range 来实现。 x

HTTP 2.0

HTTP 2.0 是 2015 年开发出来的标准,HTTP/2 的一个核心特性是使用了多路复用技术,因此它可以通过一个 TCP 连接来发送多个 URL 请求。多路复用技术能充分利用带宽,最大限度规避了 TCP 的慢启动所带来的问题。

  • 头部压缩
    • 由于 HTTP 1.1 经常会出现 User-AgentCookieAcceptServerRange 等字段可能会占用几百甚至几千字节,而 Body 却经常只有几十字节,所以导致头部偏重
    • HTTP 2.0 使用 HPACK 算法进行压缩。
  • 二进制格式
    • HTTP 2.0 使用了更加靠近 TCP/IP 的二进制格式
    • 而抛弃了 ASCII 码,提升了解析效率
  • 强化安全
    • HTTP2.0 一般都跑在 HTTPS 上。
  • 多路复用
    • 一个域名只使用一个 TCP 长连接来传输数据
    • 一个请求对应一个id,这样一个连接上可以有多个请求。
    • 通过引入二进制分帧层,就实现了 HTTP 的多路复用技术
  • 可以设置请求的优先级
  • 服务器推送

HTTP 3.0

HTTP/3 选择了一个折衷的方法——UDP 协议,基于 UDP 实现了类似于 TCP 的多路数据流传输可靠性等功能,我们把这套功能称为 QUIC 协议

  • 实现了类似 TCP 的流量控制、传输可靠性的功能。虽然 UDP 不提供可靠性的传输,但 QUIC 在 UDP 的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些 TCP 中存在的特性。
  • 集成了 TLS 加密功能。目前 QUIC 使用的是 TLS1.3,相较于早期版本 TLS1.3 有更多的优点,其中最重要的一点是减少了握手所花费的 RTT 个数
  • 实现了 HTTP/2 中的多路复用功能。和 TCP 不同,QUIC 实现了在同一物理连接上可以有多个独立的逻辑数据流(如下图)。实现了数据流的单独传输,就解决了 TCP 中的问题。
  • 实现了快速握手功能。由于 QUIC 是基于 UDP 的,所以 QUIC 可以实现使用 0-RTT 或者 1-RTT 来建立连接,这意味着 QUIC 可以用最快的速度来发送和接收数据,这样可以大大提升首次打开页面的速度。

HTTPS

HTTPS 并不是一个新的应用层协议,它其实就是 HTTP + TLS/SSL 协议组合而成,而安全性的保证正是 TLS/SSL 所做的工作。

HTTPS 就是身披了一层 SSLHTTP

探讨 HTTPS 的握手过程,其实就是 SSL/TLS 的握手过程。

TLS 旨在为 Internet 提供通信安全的加密协议。TLS 握手是启动和使用 TLS 加密的通信会话的过程。在 TLS 握手期间,Internet 中的通信双方会彼此交换信息,验证密码套件,交换会话密钥。

每当用户通过 HTTPS 导航到具体的网站并发送请求时,就会进行 TLS 握手。除此之外,每当其他任何通信使用HTTPS(包括 API 调用和在 HTTPS 上查询 DNS)时,也会发生 TLS 握手。

TLS 具体的握手过程会根据所使用的密钥交换算法的类型和双方支持的密码套件而不同

HTTPS握手过程

  1. 首先是tcp的三次握手建立连接
  2. client发送client-random+支持的加密算法集合
  3. server收到信息,返回选择一个加密算法+server-random+ 证书
  4. client验证证书有效性,并用client-random+server-random生成pre-master通过服务器公钥加密 发送给server
  5. server收到premaster,根据约定的加密算法对client-random+server-random+pre-master(解密)生成master-secret,然后发送预定成功
  6. client收到生成同样的master-secert,对称加密秘钥传输完毕

UDP 和 TCP 的区别

UDP

UDP 的全称是 {用户数据报协议|User Datagram Protocol}。它不需要所谓的握手操作,从而加快了通信速度,允许网络上的其他主机在接收方同意通信之前进行数据传输。

UDP 的特点主要有

  • UDP 能够支持容忍数据包丢失的带宽密集型应用程序
  • UDP 具有低延迟的特点
  • UDP 能够发送大量的数据包
  • UDP 能够允许 DNS 查找,DNS 是建立在 UDP 之上的应用层协议。

TCP

TCP 的全称是{传输控制协议|Transmission Control Protocol} 。它能够帮助你确定计算机连接到 Internet 以及它们之间的数据传输。通过三次握手来建立 TCP 连接,三次握手就是用来启动和确认 TCP 连接的过程。一旦连接建立后,就可以发送数据了,当数据传输完成后,会通过关闭虚拟电路来断开连接。

TCP 的主要特点有

  • TCP 能够确保连接的建立和数据包的发送
  • TCP 支持错误重传机制
  • TCP 支持拥塞控制,能够在网络拥堵的情况下延迟发送
  • TCP 能够提供错误校验和,甄别有害的数据包。

UDP VS TCP


WebSocket

WebSocket 是一种网络传输协议,可在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。

WebSocket 优点

  • 较少的控制开销。
    • 在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。
  • 更强的实时性
    • 由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于 HTTP 请求需要等待客户端发起请求服务端才能响应,延迟明显更少。
  • 保持连接状态。
    • 与 HTTP 不同的是,WebSocket 需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。
  • 更好的二进制支持。
    • WebSocket 定义了二进制帧,相对 HTTP,可以更轻松地处理二进制内容。
  • 可以支持扩展。
    • WebSocket 定义了扩展,用户可以扩展协议、实现部分自定义的子协议。

Web攻击(WebAttack)

常见的Web攻击方式有(Scirpting + Request + SQL)

  1. {跨站脚本攻击|Cross Site Scripting} (XSS)
  2. {跨站请求伪造|Cross-site Request Forgery}(CSRF)
  3. SQL注入攻击

{跨站脚本攻击|Cross Site Scripting} (XSS)

{跨站脚本攻击|Cross Site Scripting},允许攻击者将恶意代码植入到提供给其它用户使用的页面中。

XSS涉及到三方

  1. 攻击者
  2. 客户端
  3. Web应用

XSS 的攻击目标是为了盗取存储在客户端的cookie或者其他网站用于识别客户端身份的敏感信息。一旦获取到合法用户的信息后,攻击者甚至可以假冒合法用户与网站进行交互。

原理

攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。

根据攻击的来源,XSS攻击可以分成

  1. 反射型XSS:非持久化
    • 攻击者事先制作好攻击链接, 需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面
  2. 存储型XSS:持久化
    • 代码是存储在服务器中的,如在个人信息或发表文章等地方,加入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,每当有用户访问该页面的时候都会触发代码执行,这种XSS非常危险,容易造成蠕虫,大量盗窃cookie(虽然还有种DOM型XSS,但是也还是包括在存储型XSS内)。
  3. DOM型XSS:
    • 基于文档对象模型(Document Objeet Model,DOM)的一种漏洞。
    • DOM是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问和更新文档内容、结构和样式,处理后的结果能够成为显示页面的一部分。DOM中有很多对象,其中一些是用户可以操纵的,如uRI ,location,refelTer等。客户端的脚本程序可以通过DOM动态地检查和修改页面内容,它不依赖于提交数据到服务器端,而从客户端获得DOM中的数据在本地执行,如果DOM中的数据没有经过严格确认,就会产生DOM XSS漏洞。

XSS的预防

XSS攻击的两大要素:

  1. 攻击者提交而恶意代码
    • 在用户输入的过程中,过滤掉用户输入的恶劣代码,然后提交给后端
    • 如果攻击者绕开前端请求,直接构造请求就不能预防了
    • 过滤并非可靠的,容易造成前后端数据不统一
  2. 浏览器执行恶意代码
    • 在使用 .innerHTML.outerHTMLdocument.write() 时要特别小心,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用 .textContent.setAttribute()
    • 如果用 Vue/React 技术栈,并且不使用 v-html/dangerouslySetInnerHTML 功能,就在前端 render 阶段避免 innerHTMLouterHTML 的 XSS 隐患
    • DOM 中的内联事件监听器,如 locationonclickonerroronloadonmouseover 等,<a> 标签的 href 属性,JavaScript 的 eval()setTimeout()setInterval() 等,都能把字符串作为代码运行。如果不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患,请务必避免

{跨站请求伪造|Cross-site Request Forgery}

{跨站请求伪造|Cross-site Request Forgery}:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。

利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目。

触发条件

  1. 登录受信任网站A,并在本地生成Cookie。
  2. 在不登出A的情况下,访问危险网站B。

防御措施

CSRF通常从第三方网站发起,被攻击的网站无法防止攻击发生,只能通过增强自己网站针对CSRF的防护能力来提升安全性。

  1. 阻止不明外域的访问
    • 同源检测
    • Samesite Cookie
  2. 提交时要求附加本域才能获取的信息
    • CSRF Token
    • 双重Cookie验证

SQL注入

Sql 注入攻击,是通过将恶意的 Sql查询或添加语句插入到应用的输入参数中,再在后台 Sql服务器上解析执行进行的攻击。

预防方式

  • 严格检查输入变量的类型和格式
  • 过滤和转义特殊字符
  • 对访问数据库的Web应用程序采用Web应用防火墙

后记

分享是一种态度

参考资料:

  1. 趣谈网络协议
  2. 网络是如何连接的

全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。

猜你喜欢

转载自juejin.im/post/7155281413569249288