本文目录

[[toc]]

通信模型

OSI 七层模型

  • 应用层: 为用户的应用程序提供网络服务。常见的应用层协议有 HTTP(超文本传输协议)、FTP(文件传输协议)、SMTP(简单邮件传输协议)、DNS(域名系统)等。用户直接使用的各种网络应用程序(如浏览器、邮件客户端)都运行在应用层。
  • 表示层: 处理数据的表示和转换,确保不同系统之间能够正确理解和处理数据。它包括数据的加密、解密、压缩、解压缩以及数据格式的转换(如 ASCII 码与 EBCDIC 码之间的转换)等功能。
  • 会话层: 负责建立、管理和终止会话。它允许不同主机上的应用程序之间进行会话,并提供会话的同步和恢复机制。
  • 传输层: 提供端到端的可靠通信或不可靠通信服务。主要有两种协议: 传输控制协议(TCP)和用户数据报协议(UDP)。
  • 网络层: 负责将数据包从源节点传输到目标节点,处理网络中的路由选择和寻址。它使用 IP 地址来标识网络中的设备,并通过路由器来实现不同网络之间的数据包转发。常见的网络层协议有 IPv4 和 IPv6。
  • 数据链路层: 将物理层接收到的比特流封装成帧,处理帧的传输和错误检测。它分为逻辑链路控制(LLC)子层和介质访问控制(MAC)子层。MAC 子层负责控制对物理介质的访问,通过 MAC 地址来标识网络中的设备;LLC 子层则负责提供错误控制和流量控制。
  • 物理层: 负责传输比特流,定义了物理介质(如电缆、光纤、无线)的电气、机械和功能特性,包括电压、信号编码、连接器规格等。

数据传输过程

  • 应用层报文被传送到运输层
  • 在最简单的情况下,运输层收取到报文并附上附加信息,该首部将被接收端的运输层使用
  • 应用层报文和运输层首部信息一道构成了运输层报文段。附加的信息可能包括: 允许接收端运输层向上向适当的应用程序交付报文的信息以及差错检测位信息。该信息让接收端能够判断报文中的比特是否在途中已被改变
  • 运输层则向网络层传递该报文段,网络层增加了如源和目的端系统地址等网络层首部信息,生成了网络层数据报
  • 网络层数据报接下来被传递给链路层,在数据链路层数据包添加发送端 MAC 地址和接收端 MAC 地址后被封装成数据帧
  • 在物理层数据帧被封装成比特流,之后通过传输介质传送到对端
  • 对端再一步步解开封装,获取到传送的数据

TCP/IP 五层模型

TCP/IP 五层协议是在实际应用中对 OSI 七层协议的简化,它将 OSI 模型中的会话层和表示层合并到应用层,形成了五层结构

  • 应用层: 包含了 OSI 模型中应用层、表示层和会话层的功能,为用户的应用程序提供网络接口,支持各种网络应用。
  • 传输层: 提供端到端的通信服务,包括 TCP 和 UDP 两种协议,确保数据的可靠传输或快速传输。
  • 网络层: 主要功能是进行数据包的路由选择和寻址,使用 IP 协议来实现不同网络之间的通信。
  • 数据链路层: 和 OSI 模型的数据链路层一样,将比特流封装成帧,处理帧的传输和错误检测,控制对物理介质的访问。
  • 物理层: 与 OSI 模型的物理层功能相同,负责传输比特流,处理物理介质和信号传输。

TCP/IP 四层模型

TCP/IP 四层协议是另一种简化的网络模型,它在五层模型的基础上,将物理层和数据链路层合并为网络接口层,形成了四层结构

  • 应用层(Application Layer): 为用户的应用程序提供网络服务,包含了各种应用层协议,如 HTTP、FTP、SMTP 等,支持用户使用各种网络应用。
  • 传输层(Transport Layer): 提供端到端的通信服务,通过 TCP 或 UDP 协议来实现数据的可靠传输或不可靠传输,确保应用程序之间的数据传输。
  • 网络层(Internet Layer): 主要功能是进行数据包的路由选择和寻址,使用 IP 协议来实现不同网络之间的通信,确保数据包能够从源主机传输到目标主机。
  • 网络接口层(Network Interface Layer): 负责将 IP 数据包封装成适合在物理网络上传输的帧,并通过物理介质进行传输。它涵盖了 OSI 模型中物理层和数据链路层的功能,处理不同类型的网络接口和物理介质。

区别

  • OSI 七层模型: 主要用于理论研究和教学,为网络协议的设计和分析提供了一个标准的参考模型,但由于其过于复杂,在实际网络中很少直接使用。
  • TCP/IP 五层模型: 在实际网络开发和教学中被广泛使用,它既保留了 OSI 模型的分层思想,又对其进行了简化,便于理解和实现。
  • TCP/IP 四层模型: 是互联网实际使用的网络模型,它更加注重网络的实用性和效率,被广泛应用于各种网络设备和操作系统中。

DNS (Domain Names System) 协议

DNS 用于将域名对应到不同的 IP 地址中,一般分为根域名 . 、 顶级域名 comcn 、 二级域名 cctv.com 等等

DNS 查询过程

递归查询

  1. 本地 DNS 请求根域名服务器
  2. 根域名服务器请求顶级域名服务器
  3. 顶级域名服务器请求权限域名服务器
  4. 权限域名服务器发送域名对应的 IP 地址给顶级域名服务器
  5. 顶级域名服务器返回给根服务器
  6. 根服务器返回给本地 DNS

迭代查询

与递归查询类似,但是根域名服务器、顶级域名服务器只返回下一阶段的服务器地址,如根域名服务器返回顶级域名服务器地址,本地 DNS 自行请求顶级域名服务器查询权限域名服务器地址

域名缓存

  1. 浏览器缓存: 浏览器为了性能考虑自己会缓存 DNS ,不需要每次都去操作系统中查
  2. 操作系统缓存: 操作系统内部缓存有 域名/IP 映射表,不需要每次都去重新查询 DNS

浏览器中域名解析过程

  1. 检索浏览器缓存的 DNS 中是否保存有对应的 IP ,如果有,直接返回
  2. 请求本地 DNS ,本地 DNS 查询是否缓存对应 IP ,如果有,返回给浏览器
  3. 进行 DNS 迭代查询
  4. 将查询结果缓存到操作系统中,同时也发送给浏览器
  5. 浏览器接受到来自本地 DNS 的解析结果,缓存到浏览器 DNS 解析表

UDP (User Datagram Protocol, 用户数据包协议 )

无论应用层交给 UDP 多长的报文,它统统发送,一次发送一个报文,不拆分,不合并

  • UDP 不提供复杂的控制机制,利用 IP 提供面向无连接的通信服务
  • 传输途中出现丢包, UDP 也不负责重发
  • 当包的到达顺序出现乱序时, UDP没有纠正的功能。
  • 并且它是将应用程序发来的数据在收到的那一刻,立即按照原样发送到网络上的一种机制。即使是出现网络拥堵的情况, UDP 也无法进行流量控制等避免网络拥塞行为

TCP (Transmission Control Protocol, 传输控制协议 )

  • TCP 充分地实现了数据传输时各种控制功能,可以进行丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。而这些在 UDP 中都没有。
  • 此外, TCP 作为一种面向有连接的协议,只有在确认通信对端存在时才会发送数据,从而可以控制通信流量的浪费。
  • 根据 TCP 的这些机制,在 IP 这种无连接的网络上也能够实现高可靠性的通信( 主要通过检验和、序列号、确认应答、重发控制、连接管理以及窗口控制等机制实现)

三次握手

1. client to server (SYN)

  • 过程: 客户端发送 SYN 报文( SYN=1 ),携带初始序列号 ISN(c)Sequence Number )。
  • 作用:
    • 发起连接: 客户端向服务器表明建立连接的意愿。
    • 同步序列号: 告知服务器后续数据包的起始编号,用于重组和确认。
  • 缺失后果:
    • 服务器无法感知客户端的连接请求,连接无法建立。
    • 客户端无法发送数据(未进入连接状态)。

2. server answer client (SYN-ACK)

  • 过程: 服务器返回 SYN-ACK 报文( SYN=1, ACK=1 ),包含自己的初始序列号 ISN(s),并通过 ACK=ISN(c)+1 确认客户端的 SYN 报文。
  • 作用:
    • 接受连接: 服务器同意连接,并发送自身序列号。
    • 确认客户端能力: 通过回复 ACK ,证明服务器能正常接收数据。
  • 缺失后果:
    • 客户端收不到响应,会触发超时重传 SYN 报文,可能导致 SYN 洪水攻击(服务器资源被未完成的半连接耗尽)。
    • 双方序列号无法同步,后续通信混乱。

3. client answer server (ACK)

  • 过程: 客户端发送 ACK 报文( ACK=1 ),确认号为 ISN(s)+1 ,完成握手。
  • 作用:
    • 确认服务器能力: 客户端证明自己能接收服务器的数据。
    • 防止历史连接干扰: 若客户端收到旧的 SYN-ACK 报文(如网络延迟导致的重传),会忽略或发送 RST 终止无效连接。
  • 缺失后果:
    • 服务器持续等待 ACK ,占用资源维护半开连接,可能导致资源耗尽。
    • 服务器无法确认客户端已就绪,可能误发数据,造成丢包或重复传输。

为什么必须是三次握手?

两次握手的风险

若客户端发送的旧 SYN 报文因网络延迟到达服务器,服务器会误认为是新连接,直接分配资源并发送 SYN-ACK 。此时客户端可能已关闭,导致服务器资源浪费(即“历史连接问题”)。

无法确保双方收发能力均正常(例如: 服务器未确认客户端能接收数据)。

三次握手的可靠性

通过双向确认(客户端→服务器→客户端→服务器),确保双方序列号同步,且均具备发送和接收能力,避免资源浪费和数据混乱。

总结

三次握手通过 同步序列号 和 双向能力验证,解决了以下问题:

  • 防止无效历史连接占用资源。
  • 确保双方收发能力正常。
  • 协商初始序列号,为可靠传输奠定基础。

缺少任何一步都会导致连接不可靠、资源浪费或通信混乱。

四次挥手

1. client to server (FIN)

  • 过程: 主动关闭方(如客户端)发送 FIN 报文(FIN=1),并进入 FIN_WAIT_1 状态。
  • 作用:
    • 发起关闭: 通知对方(被动关闭方)不再发送数据。
    • 终止发送方向: 关闭客户端→服务器的数据传输通道。
  • 缺失后果:
    • 被动关闭方无法感知关闭请求,连接持续占用资源。
    • 客户端无法正常终止,可能重复发送数据。

2. server to client (ACK)

  • 过程: 被动关闭方(如服务器)收到 FIN 后,返回 ACK 报文(ACK=1),并进入 CLOSE_WAIT 状态。主动关闭方收到 ACK 后进入 FIN_WAIT_2 状态。
  • 作用:
    • 确认关闭请求: 告知主动方已收到终止请求。
    • 允许继续接收数据: 被动方仍可发送剩余数据(如未传完的响应)。
  • 缺失后果:
    • 主动方长期阻塞在 FIN_WAIT_1 状态,资源无法释放。
    • 被动方可能误认为连接正常,继续发送数据导致丢包。

3. client to server (FIN)

  • 过程: 被动关闭方完成数据发送后,发送 FIN 报文(FIN=1),进入 LAST_ACK 状态。
  • 作用:
    • 终止反向通道: 关闭服务器→客户端的数据传输通道。
    • 请求最终确认: 等待主动方确认连接终止。
  • 缺失后果:
    • 主动方长期停留在 FIN_WAIT_2 状态,无法释放连接资源。
    • 客户端无法感知服务器已关闭,可能重复发送 ACK

4. server to client (ACK)

  • 过程: 主动关闭方收到 FIN 后,发送 ACK 报文(ACK=1),进入 TIME_WAIT 状态(等待 2MSL 时间),最终关闭连接。被动方收到 ACK 后立即关闭。
  • 作用:
    • 确认终止请求: 确保被动方能安全释放资源。
    • 处理延迟报文: 通过 TIME_WAIT 等待旧报文消亡,避免新连接接收历史数据。
  • 缺失后果:
    • 被动方因未收到 ACK 而重传 FIN 报文,长期处于 LAST_ACK 状态。
    • 新连接可能收到旧数据,导致数据混乱。

为什么需要四次?

  • 全双工连接的独立关闭:

    TCP 连接是全双工的,每个方向需独立关闭。

    • 主动方关闭发送通道(FIN) → 被动方确认(ACK)。
    • 被动方关闭发送通道(FIN) → 主动方确认(ACK)。
  • 防止数据丢失:

    确保双方均无剩余数据需传输后再完全关闭。

https

HTTPS 的工作流程

  1. 建立连接与证书验证: 客户端发起 HTTPS 请求,服务器返回数字证书(含公钥、颁发机构、有效期等信息)。客户端验证证书合法性(如颁发机构可信性、域名匹配性、有效期等)。
  2. 密钥协商: 验证通过后,客户端生成随机对称密钥(会话密钥),用服务器公钥加密后发送至服务器。服务器使用私钥解密获取会话密钥。
  3. 对称加密通信: 双方基于协商的会话密钥进行对称加密传输数据。对称加密算法(如 AES)因其高效性被用于后续通信,而非对称加密(如 RSA)仅用于初始密钥交换。

HTTPS 认证核心流程

1. TCP 三次握手建立连接

  • 目的: 为后续加密通信提供稳定的传输通道。
  • 流程:
    1. 客户端发送 SYN 请求(同步序列号)。
    2. 服务器返回 SYN + ACK(同步+确认)。
    3. 客户端发送 ACK(最终确认),完成连接建立。

2. 证书验证阶段

  • 核心目标: 验证服务器身份合法性,防止中间人攻击。
  • 详细步骤:
    1. Server Hello: 服务器发送 SSL/TLS 证书(含公钥、域名、签发机构等信息)。
    2. 证书链验证:
      • 检查证书是否由可信 CA 签发(验证证书链完整性)。
      • 通过操作系统/浏览器内置的 CA 根证书验证签名有效性。
    3. 有效性检查:
      • 证书是否过期。
      • 证书域名是否与访问域名匹配。
      • 查询证书吊销列表(CRL/OCSP)确认未被撤销。

3. 密钥协商与交换

  • 目的: 生成对称加密会话密钥,提升后续通信效率。
  • 流程:
    1. 客户端生成随机密钥: 生成随机密钥并用服务器公钥加密。
    2. Server Key Exchange: 服务器用私钥解密获取随机密钥。
    3. 完成握手: 双方确认加密算法并切换至加密通信模式。

4. 加密数据传输

  • 机制: 使用协商的对称密钥加密所有后续通信。
  • 特点:
    • 采用 AES 等高效率对称加密算法。
    • 通过 MAC(消息认证码)保障数据完整性。

附: 双向认证流程(扩展)

  • 适用场景: 企业级应用等高安全需求场景。
  • 额外步骤:
    1. 服务器要求客户端提供证书。
    2. 客户端发送证书并由服务器验证(类似步骤2)。
    3. 双方均持有对方公钥,实现双向身份认证。
---
title: 双向认证流程图
---
sequenceDiagram
    participant 客户端
    participant 服务器
    participant CA机构

    客户端->>服务器: 发起HTTPS连接请求
    服务器->>客户端: 发送SSL证书及证书链
    客户端->>CA机构: 请求验证证书有效性
    CA机构-->>客户端: 返回验证结果
    alt 证书有效
        客户端->>客户端: 生成随机会话密钥
        客户端->>服务器: 发送公钥加密的会话密钥
        服务器->>服务器: 用私钥解密获取会话密钥
        客户端->>服务器: 开始加密通信
    else 证书无效
        客户端->>客户端: 终止连接并警告
    end

SSL 加密流程

  1. 客户端通过 URL 访问服务器建立 SSL 连接
  2. 服务端收到客户端请求后,会将网站支持的证书信息(证书中包含公钥)传送一份给客户端
  3. 客户端的服务器开始协商SSL连接的安全等级,也就是信息加密的等级
  4. 客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站
  5. 服务器利用自己的私钥解密出会话密钥
  6. 服务器利用会话密钥加密与客户端之间的通信

SSL 与 TSL 的区别

SSL 由网景公司发布,TSL 由 IETF 标准化后发布。

TSL 是 SSL 的继承者,增强了安全性,修复了 SSL 漏洞,引入新的加密方式与密钥交换机制

优化 HTTPS 请求时间

  1. 会话恢复: 通过 TLS Session Resumption(会话 ID 或 Session Tickets)复用先前协商的会话密钥,避免完整握手。
  2. OCSP Stapling: 由服务器主动提供证书状态信息,减少客户端向 CA 查询证书吊销状态的延迟。
  3. 协议与算法优化:
    • 采用 TLS 1.3(减少握手 RTT,支持 0-RTT 模式)。
    • 优先使用高效加密套件(如 AES-GCM、ChaCha20-Poly1305)。
  4. 证书优化: 使用 ECC 证书替代 RSA,缩短密钥长度并提升验证速度。
  5. CDN 与 HTTP/2: 通过 CDN 缩短物理距离,利用 HTTP/2 多路复用降低连接开销。

HTTPS 如何保证安全

  1. 服务器安全

    通过数字证书(由 CA 机构颁发)验证服务器身份真实性,建立可信通信基础。服务端在 SSL/TLS 握手阶段发送包含公钥的 CA 证书,客户端使用预置的 CA 根证书验证证书链有效性,包括:

    • 验证证书颁发机构是否受信任
    • 检查证书有效期和域名匹配性
    • 校验证书完整性(通过数字签名)
  2. 密钥协商机制
    • 非对称加密传输会话密钥: 客户端生成随机对称密钥后,使用服务器公钥加密传输(如 RSA 算法)
    • 对称加密传输业务数据: 后续通信使用协商的对称密钥(如 AES-256)加密,单次会话密钥保证前向安全性
  3. 数据完整性保护
    • 数字签名: 使用发送方私钥对报文摘要(如 SHA-256)加密,接收方用公钥解密后比对摘要值
    • 消息认证码(HMAC): 会话密钥参与的 MAC 算法生成认证标签,确保数据未被篡改

HSTS ( HTTP Strict-Transport-Security, HTTP 严格传输安全 )

这是一种 Web 安全策略机制,可以强制页面使用 HTTPS

使用 HSTS 策略后,在缓存时间内,对应的域名请求都将会自动转换为安全的 HTTPS 方法。若浏览器使用 HTTP 访问时,浏览器内部会通过 307 跳转为 HTTPS 访问,并添加响头 Non-Authorizatative-Reason: HSTS 。 并在 200 响应头字段返回 strict-transport-security: max-age=127800; [includeSubDomains;] [preload]

如果用户访问的不是安全的 HTTPS 网站时,浏览器会提示网站不安全,并禁止访问(如果没有严格安全,可以通过忽略危险继续访问)

HTST 必须使用 HTTPS 访问,并且缓存到浏览器时,才会生效。

在缓存之前,如果用户声明使用 HTTP 协议,会通过 301 重定向跳转到 HTTPS ,此时存在被中间人劫持风险,可以通过劫持跳转信息,修改 301 重定向地址,从而攻击用户。

这时候就需要使用 HSTS preload 功能,将指定域名添加到 preload list 中,浏览器只能通过 https 访问站点,避免被中间人攻击,在使用 http 访问时也会减少一次 301 重定向。

SSE (Server-Sent Events)

严格地说, HTTP 协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息( streaming )。

也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。本质上,这种通信就是以流信息的方式,完成一次用时很长的下载。

SSE 就是利用这种机制,使用流信息向浏览器推送信息。它基于 HTTP 协议,主流浏览器都支持。

优点

  • SSE 使用 HTTP 协议,现有的服务器软件都支持。 WebSocket 是一个独立协议。
  • SSE 属于轻量级,使用简单; WebSocket 协议相对复杂。
  • SSE 默认支持断线重连, WebSocket 需要自己实现。
  • SSE 一般只用来传送文本,二进制数据需要编码后传送, WebSocket 默认支持传送二进制数据。
  • SSE 支持自定义发送的消息类型。

客户端示例

// 判断是否支持 SSE
if ('EventSource' in window) {
  const source = new EventSource(url, {
    // 跨域时,使用此配置让 SSE 发送请求时携带 cookie
    withCredentials: true,
  })

  // 判断当前连接状态
  switch (source.readyState) {
    case EventSource.CONNECTING:
      // EventSource.CONNECTING = 0
      // 表示连接还未建立,或者断线正在重连。
      break
    case EventSource.OPEN:
      // EventSource.OPEN = 1
      // 表示连接已经建立,可以接受数据。
      break
    case EventSource.CLOSED:
      // EventSource.CLOSED = 2
      // 表示连接已断,且不会重连。
      break

    default:
      break
  }

  // 建立连接时
  source.onopen = function (event) {
    // 连接建立时的回调
  }
  // 回调的另一种写法
  source.addEventListener('open', (event) => {
    // 连接建立时的回调
  }, false)

  // 处理消息
  source.onmessage = function (event) {
    const data = event.data
    // handle message
  }
  // 处理消息的另一种写法,如果服务端发送的是自定义事件,则必须使用这种写法
  // 并将 message 替换为自定义事件名
  source.addEventListener('message', (event) => {
    const data = event.data
    // handle message
  }, false)

  // 处理错误
  source.onerror = function (event) {
    // handle error event
  }
  // 处理错误的另一种写法
  source.addEventListener('error', (event) => {
    // handle error event
  }, false)

  // 主动关闭连接
  source.close()
}

服务端示例

响应必须携带以下响应头

Content-Type: text/event-stream  # 必须指定 MIME 类型为event-steam
Cache-Control: no-cache
Connection: keep-alive

# 每一次发送的信息,由若干个 message 组成,每个 message 之间用 \n\n 分隔。
# 每个 message 内部由若干行组成,每一行都是如下格式。

: 这是单行注释,通过不同的前缀可以区分不同的消息,使用 ID 将唯一表示数据
: ID 在请求中断时,会放到 `Last-Event-ID` 请求头中发送给服务端,用于重建连接
id: msg1\n
data: some text\n\n

: 使用 event 声明以下消息要触发 foobar 事件,数据内容为 data 中声明的内容
event: foobar\n
data: another message\n
data: {"username": "bobby", "time": "02:33:48"}\n\n

: 让客户端在指定时间间隔后再尝试重连
retry: 10000\n

HTTP

常见状态码

1xx 代表请求已被接受,需要继续处理

  • 100(客户端继续发送请求,这是临时响应): 这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。服务器必须在请求完成后向客户端发送一个最终响应
  • 101: 服务器根据客户端的请求切换协议,主要用于websocket或http2升级

2xx 代表请求已成功被服务器接收、理解、并接受

  • 200(成功): 请求已成功,请求所希望的响应头或数据体将随此响应返回
  • 201(已创建): 请求成功并且服务器创建了新的资源
  • 202(已创建): 服务器已经接收请求,但尚未处理
  • 203(非授权信息): 服务器已成功处理请求,但返回的信息可能来自另一来源
  • 204(无内容): 服务器成功处理请求,但没有返回任何内容
  • 205(重置内容): 服务器成功处理请求,但没有返回任何内容
  • 206(部分内容): 服务器成功处理了部分请求

3xx 表示要完成请求,需要进一步操作。

  • 300(多种选择): 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择
  • 301(永久移动): 永久重定向
  • 302(临时移动): 临时重定向,禁止被缓存
  • 303(查看其他位置): 临时重定向,允许改变方法,禁止被缓存
  • 304(命中缓存): 协商缓存,告诉客户端有缓存,直接使用缓存中的数据,返回页面的只有头部信息,是没有内容部分
  • 305 (使用代理): 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理
  • 307 (临时重定向): 临时重定向,不允许改变方法,禁止被缓存
  • 308 (永久重定向): 永久重定向,不允许改变方法

4xx 代表了客户端看起来可能发生了错误,妨碍了服务器的处理

  • 400(错误请求): 服务器不理解请求的语法
  • 401(未授权): 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
  • 403(禁止): 服务器拒绝请求
  • 404(未找到): 服务器找不到请求的网页
  • 405(方法禁用): 禁用请求中指定的方法
  • 406(不接受): 无法使用请求的内容特性响应请求的网页
  • 407(需要代理授权): 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理
  • 408(请求超时): 服务器等候请求时发生超时

5xx 表示服务器无法完成明显有效的请求。这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生

  • 500(服务器内部错误): 服务器遇到错误,无法完成请求
  • 501(尚未实施): 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码
  • 502(错误网关): 服务器作为网关或代理,从上游服务器收到无效响应
  • 503(服务不可用): 服务器目前无法使用(由于超载或停机维护)
  • 504(网关超时): 服务器作为网关或代理,但是没有及时从上游服务器收到请求
  • 505(HTTP 版本不受支持): 服务器不支持请求中所用的 HTTP 协议版本

常见请求头

字段名说明示例
Accept能够接受的回应内容类型(Content-TypesAccept: text/plain
Accept-Charset能够接受的字符集Accept-Charset: utf-8
Accept-Encoding能够接受的编码方式列表Accept-Encoding: gzip, deflate
Accept-Language能够接受的回应内容的自然语言列表Accept-Language: en-US
Authorization用于超文本传输协议的认证的认证信息Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Cache-Control用来指定在这次的请求/响应链中的所有缓存机制 都必须 遵守的指令Cache-Control: no-cache
Connection该浏览器想要优先使用的连接类型Connection: keep-alive
Cookie服务器通过 Set-Cookie 发送的一个 超文本传输协议 CookieCookie: $Version=1; Skin=new;
Content-Length以 八位字节数组 (8位的字节)表示的请求体的长度Content-Length: 348
Content-Type请求体的 多媒体类型Content-Type: application/x-www-form-urlencoded
Date发送该消息的日期和时间Date: Tue, 15 Nov 1994 08:12:31 GMT
Expect表明客户端要求服务器做出特定的行为Expect: 100-continue
Host服务器的域名(用于虚拟主机 ),以及服务器所监听的传输控制协议端口号Host: en.wikipedia.org:80 Host: en.wikipedia.org
If-Match仅当客户端提供的实体与服务器上对应的实体相匹配时,才进行对应的操作。主要作用时,用作像 PUT 这样的方法中,仅当从用户上次更新某个资源以来,该资源未被修改的情况下,才更新该资源If-Match: "737060cd8c284d8af7ad3082f209582d"
If-Modified-Since允许在对应的内容未被修改的情况下返回304未修改If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
If-None-Match允许在对应的内容未被修改的情况下返回304未修改If-None-Match: "737060cd8c284d8af7ad3082f209582d"
If-Range如果该实体未被修改过,则向我发送我所缺少的那一个或多个部分;否则,发送整个新的实体If-Range: "737060cd8c284d8af7ad3082f209582d"
Range仅请求某个实体的一部分Range: bytes=500-999
User-Agent浏览器的浏览器身份标识字符串User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0
Origin发起一个针对跨来源资源共享的请求Origin: http://www.example-social-network.com

相似请求头的区别

请求头作用场景字段内容是否必填安全性
Host请求的 目标服务器域名 ,由浏览器根据请求的 URL 自动填充域名 + 端口HTTP/1.1 必填无敏感路径信息,但可能被用于攻击
Origin表示 请求的“源”(协议 + 域名 + 端口) ,用于跨域请求的权限控制(如 CORS)协议 + 域名 + 端口仅在跨域或非简单请求时存在较 Referer 更安全(无路径信息)
Referer当前请求的来源页面完整 URL (包含路径)协议+域名+端口+路径(不含哈希和用户信息)非必填,浏览器自动生成可能暴露用户隐私(如 URL 参数)

HTTP 1.0

HTTP 1.0 浏览器与服务器只保持短暂的连接,每次请求都需要与服务器建立一个TCP连接

服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求

简单来讲,每次与服务器交互,都需要新开一个连接,每次发送请求都需要重新握手与挥手

如果需要建立长连接,需要设置一个非标准的 Connection 字段 Connection: keep-alive

HTTP 1.1

在HTTP1.1中,默认支持长连接(Connection: keep-alive),即在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟

建立一次连接,多次请求均由这个连接完成

同时,HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间

同时,HTTP1.1在HTTP1.0的基础上,增加更多的请求头和响应头来完善的功能,如下:

  • 引入了更多的缓存控制策略,如 If-Unmodified-Since , If-Match, If-None-Match 等缓存头来控制缓存策略
  • 引入 range ,允许值请求资源某个部分
  • 引入 host ,实现了在一台 WEB 服务器上可以在同一个 IP 地址和端口号上使用不同的主机名来创建多个虚拟 WEB 站点

并且还添加了其他的请求方法: putdeleteoptions

HTTP/2

HTTP/2 在相比之前版本,性能上有很大的提升,添加了以下特性:

  • 传输数据量大幅度减少
    • 以二进制方式传输
    • 头部压缩: 传输时,第一个消息带有完整的请求头,第二个消息只带有与上一个消息有差异的请求头
  • 多路复用以及相关功能:
    • 消息优先级: 每个数据流有优先级 ( 1-256 ) ,数据流之间可以有依赖关系
  • 服务器推送:
    • 并行推送消息

核心概念

  • Connection: 连接。 一个 TCP 连接。包含一个或多个 Stream
  • Stream: 数据流。 一个双向通讯的数据流,包含多条 Message
  • Message: 消息。 对应 HTTP1 中的请求或者响应,包含一条或多条 Frame
  • Frame: 数据帧。 最小单位,以二进制压缩格式存放 HTTP1 中的内容

多路复用

HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了”队头堵塞”

队头堵塞: TCP 将会分包发出,并且由于滑动窗口的控制可以一次性发出多个数据包,接收方按照编号接收处理,如果头部编号的包丢失,后续的数据包会被堵塞,等待头部数据包重传完成才能处理。

二进制分帧

帧是 HTTP/2 通信中最小单位信息

HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,解析起来更高效

将请求和响应数据分割为更小的帧,并且它们采用二进制编码

HTTP/2 中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流

每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装,这也是多路复用同时发送数据的实现条件

头部压缩

HTTP/2 在客户端和服务器端使用“ head 表”来跟踪和存储之前发送的键值对,对于相同的数据,不再通过每次请求和响应发送

head 表在 HTTP/2 的连接存续期内始终存在,由客户端和服务器共同渐进地更新

服务器推送

HTTP/2 引入服务器推送,允许服务端推送资源给客户端

服务器会顺便把一些客户端需要的资源一起推送到客户端,如在响应一个页面请求中,就可以随同页面的其它资源

免得客户端再次创建连接发送请求到服务器端获取

这种方式非常合适加载静态资源

HTTP3

放弃 TCP 协议的原因

  • 建立连接时延大: HTTPS 初次连接( TCP 握手 + TLS 握手 )需要 3 个 RTT 才能建立
  • 队头阻塞问题: 以 HTTP2 为例,一个 TCP 连接上的所有 stream (流,HTTP/2 传输的数据单元) 必须按顺序依次传输 。如果一个 stream 丢失,后面的 stream 将被阻塞,直到丢失的数据重传。
  • 协议僵化问题: 作为一个运行了接近 40 多年的协议,许多中间设备(如防火墙和路由器)已经依赖某些隐式规则,打补丁或者说推动 TCP 协议更新脱离现实。

QUIC 介绍

QUIC 是基于 UDP 实现的 可靠 数据传输协议,可以 更低延迟更高吞吐

QUIC 特性

  • 支持连接迁移

网络从 WiFi 变更为 4G 时, TCP 使用四元组(源 IP 、源端口、目标 IP 、目标端口)标识,而 QUIC 使用 Connection ID 作为标识。

在网络变化导致源 IP 变化时, QUIC Connection ID 不会变更,所以使用 TCP 协议的 HTTP1/1.1/2 都需要重新连接,而 HTTP3 则不需要。

  • 低时延连接

QUIC 内部集成了 TLS 安全协议,无需像 TCP 先经过三次握手,再经过 TLS 握手才开启数据传输。QUIC 初次连接只需要 1- RTT 就能开启数据传输

  • TCP + TLS1.2 ( 2 RTT ) + HTTP = 3 RTT ( TCP 的 RTT 与 TLS1.2 的第一个 RTT 可以重叠 )
  • TCP + TLS1.3 + HTTP = 2 RTT ( TCP 的 RTT 与 TLS1.3 的 RTT 可以重叠 )
  • QUIC + HTTP2 = 1 RTT ( QUIC 的 RTT 与 HTTP 的 RTT 可以重叠 )
  • 可插拔拥塞控制

TCP 内置了滑动窗口进行拥塞控制,修改算法跟操作系统内核挂钩,可能需要升级操作系统内核版本才行。 QUIC 支持灵活 “插拔” 不同的拥塞控制算法,如 Cubic 、 BBR 、 PCC ,这让工程师在无需深入内核开发的情况下,能灵活调整可靠传输机制和拥塞控制策略。如 Cloudflare 开发的开源 QUIC 实现 quiche,提供了 setSendAlgorithm 方法,工程师可直接选择合适的拥塞控制算法,无需经过操作系统内核。

  • 降低对丢包的影响

若一个属于 Stream2 的 TCP 数据包丢失,将导致后续数据包的传输阻塞。该问题就是业界常常提到的“队头阻塞”(head-of-line blocking)。 相比之下,QUIC 为每个 Stream 设计了独立的控制机制, Stream 之间没有先后依赖。这意味着,如果一个属于 Stream2 的 UDP 数据包丢失,它只会影响 Stream2 的处理,不会阻塞 Stream1 和 Stream3 的传输。 这样的设计有效避免了 TCP 协议中的队头阻塞问题。

QUIC 困境

  • 服务端层面: 不仅需要适配 QUIC 协议,还要确保与 TCP 协议兼容。此外,TCP 经过多年的深度优化,QUIC 实际的效能表现是否能够与 TCP 相媲美?
  • 客户端层面: 需要在适配、收益之间进行成本权衡。采用 QUIC 协议的客户端必须具备降级容错能力,并准备长时间同时维护新旧两种网络库。

CDN (Content Delivery Network, 内容分发网络 )

CDN 最大的作用是根据用户位置分配最近的资源,这样可以减少数据传输距离,让请求更快响应

负载均衡系统

CDN 在 DNS 解析阶段,不会返回 IP 地址,而是返回 CNAME 。

由于没有返回 IP 地址,于是本地 DNS 会向负载均衡系统再发送请求,则进入到 CDN 的全局负载均衡系统进行智能调度:

  • 看用户的 IP 地址,查表得知地理位置,找相对最近的边缘节点
  • 看用户所在的运营商网络,找相同网络的边缘节点
  • 检查边缘节点的负载情况,找负载较轻的节点
  • 其他,比如节点的“健康状况”、服务能力、带宽、响应时间等

结合上面的因素,得到最合适的边缘节点,然后把这个节点返回给用户,用户就能够就近访问CDN的缓存代理

缓存代理

缓存系统是 CDN 的另一个关键组成部分,缓存系统会有选择地缓存那些最常用的那些资源

其中有两个衡量 CDN 服务质量的指标:

  • 命中率: 用户访问的资源恰好在缓存系统里,可以直接返回给用户,命中次数与所有访问次数之比
  • 回源率: 缓存里没有,必须用代理的方式回源站取,回源次数与所有访问次数之比

缓存系统也可以划分出层次,分成一级缓存节点和二级缓存节点。一级缓存配置高一些,直连源站,二级缓存配置低一些,直连用户

回源的时候二级缓存只找一级缓存,一级缓存没有才回源站,可以有效地减少真正的回源

现在的商业 CDN命中率都在 90% 以上,相当于把源站的服务能力放大了 10 倍以上

WebSocket

全双工

通信允许数据在两个方向上同时传输,它在能力上相当于两个单工通信方式的结合,服务端可以主动往客户端推送数据。

二进制帧

采用了二进制帧结构,语法、语义与 HTTP 完全不兼容,相比 HTTP/2WebSocket 更侧重于“实时通信”,而 HTTP/2 更侧重于提高传输效率,所以两者的帧结构也有很大的区别

不像 HTTP/2 那样定义流,也就不存在多路复用、优先级等特性

自身就是全双工,也不需要服务器推送

协议名

引入 wswss 分别代表明文和密文的 WebSocket 协议,且默认端口使用 80 或 443 ,几乎与 HTTP 一致

握手

发送请求

  • Connection: 必须设置 Upgrade ,表示客户端希望连接升级
  • Upgrade: 必须设置 WebSocket ,表示希望升级到 WebSocket 协议
  • Sec-WebSocket-Key: 客户端发送的一个 base64 编码的密文,用于简单的认证秘钥。要求服务端必须返回一个对应加密的 Sec-WebSocket-Accept 应答,否则客户端会抛出错误,并关闭连接
  • Sec-WebSocket-Version: 表示支持的 WebSocket 版本

示例请求:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

返回响应

  • 响应行: 表示服务端接受 WebSocket 协议的客户端连接
  • Sec-WebSocket-Accep: 验证客户端请求报文,同样也是为了防止误连接。具体做法是把请求头里 Sec-WebSocket-Key 的值,加上一个专用的 UUID ,再计算摘要
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=Sec-WebSocket-Protocol: chat

优点

  • 较少的控制开销: 数据包头部协议较小,不同于 HTTP 每次请求需要携带完整的头部
  • 更强的实时性: 相对于 HTTP 请求需要等待客户端发起请求服务端才能响应,延迟明显更少
  • 保持创连接状态: 创建通信后,可省略状态信息,不同于 HTTP 每次请求需要携带身份验证
  • 更好的二进制支持: 定义了二进制帧,更好处理二进制内容
  • 支持扩展: 用户可以扩展 WebSocket 协议、实现部分自定义的子协议
  • 更好的压缩效果: WebSocket 在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率

缺点

  • 数据分片后有序传输,也就不支持多路复用,所以依旧存在 HTTP1.1 的队头阻塞问题
  • 不支持数据压缩

GET/POST 区别

GET

  • 请求一个指定资源的表示形式,使用GET的请求应该只被用于获取数据
  • 在浏览器回退时是无害的
  • URL 地址可以被书签收藏
  • 请求会被浏览器主动 cache
  • 请求参数只能进行 url 编码
  • 请求参数会被完整保留在浏览器历史记录里
  • 在 URL 中传送的参数是有长度限制的,整个 URL 长度一般不超过 2083 (2048 + 35)
  • 参数只接受ASCII字符
  • 参数直接暴露在 URL 上,不能传递敏感数据
  • 参数通过 URL 传递
  • 请求参数一般跟 header 一起发送

POST

  • 将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用
  • 在浏览器回退时会再次提交请求
  • URL 地址一般不可以被书签收藏
  • 请求不会被浏览器主动 cache ,必须手动设置
  • 请求参数支持多种编码方式
  • 请求参数不会被浏览器保留
  • 请求参数是没有长度限制,但是参数过大可能导致请求超时
  • 参数没有限制,可以是二进制、文本、图片等等
  • 参数需要抓包才能看到, URL 中不会体现,可以传递敏感数据
  • 参数通过 request body 传递
  • 可能会先发送 header ,服务器响应 100 continue ,再发送 data