应用层

ZaynPei Lv6

应用层是 OSI 参考模型的最高层 (第 7 层),也是 TCP/IP 体系结构事实上的顶层。它是离用户最近的一层。

它的根本目标是通过应用进程之间的交互来实现特定的网络应用。我们平时使用的各种网络功能,如网页浏览、文件下载、电子邮件、在线游戏等,都是在应用层实现的。可以说,设计和建立计算机网络的最终目的,就是为了运行应用层上的各种应用程序,满足用户的需求

同时, 应用层开发也具有很高的便利性. 网络应用程序只运行在端系统(用户的计算机、服务器等)上, 传输层已经为应用进程提供了端到端的逻辑通信服务(TCP 或 UDP)。开发者无需关心底层网络核心的复杂细节,如路由器的选择、数据包的转发等。

客户/服务器方式和对等方式

在开发一个新的网络应用时,首先要考虑的问题是:这个应用的程序如何在不同的端系统上组织?它们之间是什么关系?目前主要有两种流行的体系结构。

客户/服务器方式 (Client/Server, C/S)

这是最传统、最成熟的网络应用模型。它将应用程序分为两个部分:客户端和服务器。客户端是向服务器请求服务的应用程序,而服务器是提供服务的应用程序。客户端和服务器之间通过网络进行通信。

服务器 (Server):指运行服务器程序的应用进程。

  • 它是服务的提供方, 通常持续运行被动地等待客户的请求。
  • 具有固定的 IP 地址熟知的传输层端口号(如 Web 服务器的 80 端口)。

客户 (Client):指运行客户程序的应用进程。

  • 它是服务的请求方, 主动向服务器发起请求
  • 客户端计算机的 IP 地址通常是动态的,使用的端口号也是临时的。

模型特点:

  • 服务集中型: 应用服务集中在少数(通常性能强大)的服务器计算机上。
  • 不对等关系: 客户和服务器的角色固定,功能不同。

优点: - 易于管理和维护(服务集中)。 - 安全性相对容易控制。

缺点: - 可扩展性问题: 当客户数量激增时,单一服务器容易成为性能瓶颈 。 - 成本较高: 需要购买和维护高性能的服务器硬件及带宽。 - 单点故障: 如果服务器宕机,整个服务就会中断。

解决方案 (针对缺点): 使用服务器集群 (Server Cluster) 或服务器场 (Server Farm) 来构建一个强大的“虚拟服务器”,以提高处理能力和可靠性 。

典型应用: 万维网 (WWW)、文件传送 (FTP)、电子邮件 (Email)、数据库访问等。

对等方式 (Peer-to-Peer, P2P)

这是一种相对较新的、与 C/S 模型截然不同的结构。其核心概念是对等关系

P2P没有固定的客户和服务器角色, 网络边缘端系统上的应用进程互称对等方(Peer)。每个对等方既是服务的请求者,又是服务的提供者, 对等方之间直接通信。

模型特点: - 服务分散型: 服务能力分布在大量对等方的计算机上,这些计算机通常是个人拥有并控制的 。 - 对等关系: 所有参与者的角色和功能相似。

优点: - 高度可扩展性: 每增加一个对等方,不仅增加了服务需求,同时也增加了服务提供能力。系统性能不会因规模增大而降低(甚至可能提高)。 - 成本低廉: 通常不需要庞大的服务器设施和带宽投入 。 - 鲁棒性 (Robustness): 不存在单点故障,部分对等方离线不影响整个系统的运行。

缺点: - 管理复杂:资源分散,难以集中管理和控制。 - 安全性问题:内容来源多样,可能存在安全风险或版权问题。 - 性能不稳定:对等方的在线时间和带宽不稳定,可能影响服务质量。

典型应用: P2P文件共享 (如 BitTorrent)、即时通信 (部分功能)、P2P 流媒体 (如某些直播)、分布式存储 。

此外, 目前还演进出了混合模式:许多现代应用会混合使用 C/S 和 P2P 模式 。例如,用户登录和好友列表可能依赖中心服务器 (C/S),而文件传输或音视频通话则采用 P2P 直接连接。

动态主机配置协议 (DHCP)

任何一台主机想要接入 TCP/IP 网络(如因特网)并与其他主机正常通信,都必须首先配置好一系列关键的网络参数。这些参数就像主机的“网络身份证”和“导航地图”,主要包括 :

  • IP 地址 (IP Address): 主机在网络中的唯一标识符,就像门牌号。

  • 子网掩码 (Subnet Mask): 用于区分 IP 地址中的网络部分和主机部分,帮助主机判断通信目标是在本地子网还是需要通过路由器转发。

  • 默认网关的 IP 地址 (Default Gateway IP Address): 当主机需要与本地子网之外的主机通信时,数据包需要发送给这个“网关”(通常是路由器)进行转发。

  • 域名服务器 (DNS) 的 IP 地址 (DNS Server IP Address): 主机需要通过 DNS 服务器将易于记忆的域名(如 www.google.com)解析成 IP 地址才能进行访问。

在早期或小型网络中,这些参数可以通过操作系统提供的工具(图形界面或命令行)手动配置在每台主机上。主机会将这些配置保存在一个文件中,并在每次启动时读取使用。

但是随着网络规模的扩大和移动设备的普及,手工配置网络参数暴露出诸多不便和问题 :

  • 工作量巨大且易出错 (对于管理员):想象一下在一个拥有数百甚至数千台主机的企业或校园网络中,网络管理员需要为每一台机器逐一手动输入上述所有参数。这不仅是一项极其繁琐、耗时的工作,而且非常容易出错(例如输错 IP 地址、掩码或网关),导致主机无法正常联网 。

  • 不方便且易出错 (对于用户):对于经常需要在不同网络环境(如家中、办公室、咖啡馆)中使用笔记本电脑的用户来说,每次更换地点都需要重新手动修改网络配置,这非常不方便 。用户可能不清楚每个网络环境的具体参数,或者在配置过程中出错。

动态主机配置协议的作用

为了解决手工配置带来的种种问题,动态主机配置协议 (Dynamic Host Configuration Protocol, DHCP) 应运而生。

DHCP 允许网络中的主机自动获取所需的网络配置参数,而无需人工干预。

实现方式是, 网络管理员先在网络中部署一台 DHCP 服务器

  • DHCP 服务器集中配置好可供分配的网络参数范围(如 IP 地址池、子网掩码、默认网关地址、DNS 服务器地址等)。
  • 网络中的客户端主机(如 PC、笔记本电脑、手机)在开机或接入网络时,会自动运行 DHCP 客户端程序
  • DHCP 客户端会自动向网络中的 DHCP 服务器请求配置参数
  • DHCP 服务器收到请求后,会从预设的配置分配一套参数给客户端 。

最终, 主机可以实现“即插即联网” (Plug-and-Play Networking),极大地简化了网络管理和用户操作。这种自动化的方式解决了大规模网络和移动设备场景下网络参数配置的复杂性和易错性问题,是现代网络不可或缺的基础服务之一。

DHCP 的工作流程

DHCP 采用客户/服务器 (C/S) 模式工作 。用户主机上运行 DHCP 客户进程,网络中至少有一台服务器运行 DHCP 服务器进程。在理解 DHCP 的工作流程前,我们需要先理解 DHCP 报文如何在网络中传输:

  • 应用层协议: DHCP 本身是就一个应用层协议
  • 传输层: 它使用 UDP 作为传输层协议 。
    • DHCP 服务器监听 UDP 的熟知端口号 67
    • DHCP 客户使用 UDP 的熟知端口号 68
  • 封装过程:
    • DHCP 报文(如 DHCP 发现报文)首先被封装成 UDP 用户数据报,包含源端口 68 和目的端口 67
    • UDP 用户数据报再被封装成 IP 数据报 。
    • IP 数据报最后根据网络接口类型(如以太网)封装成相应的数据链路层帧进行传输 alt text

DHCP 的核心交互过程通常被称为 DORA,代表四个主要报文:Discover, Offer, Request, Acknowledge。此外还包括租约的更新释放过程。 alt text 场景假设: 网络中有一台新主机(DHCP 客户)需要获取网络配置,同时有两台 DHCP 服务器(服务器1 和 服务器2)可以提供服务。

步骤 1:发现服务器 (DHCP DISCOVER) - 客户广播

  • 主机启动 DHCP 客户端后,它不知道网络中有哪些 DHCP 服务器,也不知道它们的地址。因此,它会广播发送一个 DHCP 发现报文 (DHCP DISCOVER) 。

  • 封装细节:

    • UDP:源端口 68,目的端口 67 。
    • IP:源 IP 地址为 0.0.0.0 (因为客户还没有 IP),目的 IP 地址为广播地址 255.255.255.255 。
    • DHCP 报文内部:包含一个事务 ID (Transaction ID) 和客户的 MAC 地址
  • 结果:网络中所有主机都会收到这个广播包,但只有 DHCP 服务器会处理它

步骤 2:提供租约 (DHCP OFFER) - 服务器响应

  • 收到 DISCOVER 报文的 DHCP 服务器(假设服务器1和服务器2都收到了)会各自准备一个配置方案

  • 服务器内部操作:查找数据库,看是否有为该 MAC 地址预留的配置。如果没有,则从 IP 地址池中挑选一个可用的 IP 地址 。

    • 服务器在提供 IP 地址前,会先使用 ARP 检查该 IP 是否已被网络中其他主机占用
  • 发送报文: 每个服务器都发送一个 DHCP 提供报文 (DHCP OFFER) 。

  • 封装细节:

    • IP:源 IP 地址为服务器自身的 IP,目的 IP 地址仍然是广播地址 255.255.255.255 (因为客户此时可能还无法接收单播) 。

    • DHCP 报文内部:包含提供的 IP 地址子网掩码地址租期 (Lease Time)、默认网关 IPDNS 服务器 IP 等配置信息,以及与 DISCOVER 报文匹配的事务 ID

  • 客户动作: 客户可能会收到多个 DHCPOFFER 报文(来自服务器1和服务器2)。它会根据事务 ID 确认是自己请求的响应,然后从中选择一个(通常选择最先到达的那个)。

步骤 3:请求租约 (DHCP REQUEST) - 客户广播

  • 客户选择好一个 OFFER 后(假设选择了服务器1的 OFFER),需要向所有服务器确认这个选择,并正式请求使用该租约。它会广播发送一个 DHCP 请求报文 (DHCP REQUEST) 。

  • 封装细节:

    • IP:源 IP 地址仍为 0.0.0.0 (因为租约尚未最终确认),目的 IP 地址为广播地址 255.255.255.255
    • DHCP 报文内部:包含事务 ID、客户 MAC 地址、接收到的租约中的 IP 地址、提供此租约的 DHCP 服务器的 IP 地址 (明确告知选择了谁) 等信息 。
  • 结果:所有 DHCP 服务器都会收到这个 REQUEST。

    • 被选中的服务器(服务器1)知道客户接受了它的 OFFER。
    • 未被选中的服务器(服务器2)知道客户拒绝了它的 OFFER,可以收回之前预留的 IP 地址。

步骤 4:确认租约 (DHCP ACK) - 服务器响应

  • 被选中的 DHCP 服务器(服务器1)发送 DHCP 确认报文 (DHCP ACK) 来最终确认租约 。

  • 封装细节:

    • IP:源 IP 为服务器1 的 IP,目的 IP 仍然可能是广播地址 255.255.255.255 (取决于客户请求时的 BROADCAST 标志位,见后述) 。
  • 客户动作:客户收到 DHCP ACK 后,租约正式生效。

    • 客户在使用这个 IP 地址之前,还会主动发送 ARP 请求,再次确认该 IP 地址没有被网络中其他主机占用 。
    • 如果 ARP 检测到冲突,客户会向服务器发送 DHCP 谢绝报文 (DHCP DECLINE),并重新开始 DHCP 过程(发送 DISCOVER) 。
    • 如果 ARP 未检测到冲突,客户就配置好所有网络参数,可以正常通信了。

IP 地址租约的更新 (续约)

DHCP 分配的 IP 地址通常有一个租用期限 (Lease Time)。客户端需要在租约到期前进行续约,否则将失去该 IP 地址的使用权。

T1 时间点 (租用期过半):

  • 客户会单播向当初提供租约的 DHCP 服务器(服务器1)发送 DHCP REQUEST 报文请求续约

  • 此时 IP 源地址是客户当前租用的 IP,目的 IP 是服务器1 的 IP 。

  • 服务器响应:

    • 同意 (DHCP ACK): 服务器回复 DHCP ACK,客户获得新的租期。
    • 不同意 (DHCP NACK): 服务器回复 DHCP NACK。客户必须立即停止使用当前 IP,并重新开始 DORA 过程(广播 DISCOVER) 。
    • 无响应:服务器可能宕机或网络不通 。

T2 时间点 (租用期过了 87.5%):

  • 如果在 T1 时服务器未响应,客户会等到租用期的 87.5% 时广播发送 DHCP REQUEST 报文,尝试向任何可达的 DHCP 服务器续约。

如果仍然没有服务器响应,则当租约最终到期后,客户必须立即停止使用该 IP,并重新开始 DORA 过程。

不过, 客户也可以随时提前终止租约(例如正常关机时)。

  • 报文: 客户向 DHCP 服务器发送 DHCP 释放报文 (DHCP RELEASE) 。

  • 封装: IP 源地址为 0.0.0.0,目的地址为广播地址 255.255.255.255 。服务器收到后,可以将该 IP 地址回收并分配给其他客户。

关于广播与单播响应的补充 (BROADCAST 标志位) 在 DHCP 交互的早期阶段(客户还没有有效 IP 地址时),客户的 TCP/IP 协议栈可能无法正确处理发送给它的单播 IP 数据报。 解决方案是:DHCP 客户可以在发送 DISCOVER 和 REQUEST 报文时,设置一个 “BROADCAST” 标志位 。 - 标志位 = 1: 客户明确告知服务器:“请使用广播方式回复我(发送 OFFER 和 ACK)” 。 - 标志位 = 0: 客户告知服务器:“我能接收单播,请使用单播方式回复我” 。此时,服务器会根据 DISCOVER/REQUEST 报文中客户提供的 MAC 地址来发送单播帧 。

这个机制增强了 DHCP 对不同 TCP/IP 协议栈实现的兼容性 。

DHCP 中继代理

我们知道, DHCP 客户在启动时发送的 DHCP DISCOVER 报文是一个广播报文(目的 IP 地址为 255.255.255.255)。

而路由器的一个基本工作原则就是隔离广播域,它们不会转发广播报文。

假设 DHCP 客户(主机1, 主机n)位于一个子网,而 DHCP 服务器位于另一个不同的子网,两者之间通过路由器连接。

这会导致客户发送的广播 DHCP DISCOVER 报文到达路由器时,会被路由器直接丢弃,永远无法到达位于另一个子网的 DHCP 服务器。因此,这些客户将无法通过 DHCP 自动获取网络配置参数。

为了解决广播报文不能跨越路由器的问题,引入了 DHCP 中继代理 (DHCP Relay Agent) 的概念 。

实现方式通常是在路由器上启用并配置 DHCP 中继代理功能, 指向真正 DHCP 服务器的 IP 地址

其工作过程如下:

  1. 接收广播: 启用了中继代理功能的路由器(位于客户子网)在其接口上收到来自 DHCP 客户的广播 DHCP DISCOVER 报文。

  2. 转换为单播: 路由器(中继代理)不会丢弃这个广播报文。相反,它会将该报文重新封装成一个单播 IP 数据报。

  3. 这个单播报文的目的 IP 地址被设置为配置好的真正 DHCP 服务器的 IP 地址, 源 IP 地址通常是路由器接收到广播报文的那个接口的 IP 地址(这样服务器就知道是哪个子网的请求)。

  4. 单播转发: 路由器将这个单播报文转发给 DHCP 服务器 。

  5. 服务器响应: DHCP 服务器处理这个请求(如同直接收到 DISCOVER 一样),然后将 DHCP OFFER 报文(或其他响应报文)单播发送回给中继代理(路由器)。

  6. 中继转发给客户: 中继代理收到服务器的响应后,再将其转发给最初发起请求的 DHCP 客户(通常使用广播或根据客户 MAC 地址单播)。

  7. 后续交互: DHCP 客户与服务器之间的后续报文(如 DHCP REQUEST, DHCP ACK)都会通过这个中继代理进行转发。

上述就是DHCP中继代理的工作过程, 其主要优势在于实现了集中管理, 我们不必在每一个子网(或 VLAN)上都部署一台 DHCP 服务器 。

从而减少服务器数量:通过使用中继代理,可以在一个中心位置部署少量(甚至一台)DHCP 服务器,来为整个网络(包含多个子网)提供服务。这极大地简化了 DHCP 服务器的管理和维护工作 。

域名系统(DNS)

我们在上网时,更习惯使用域名 (Domain Name) 来访问网站,例如 www.google.com 或 cnnic.net.cn 。因为域名通常具有一定的含义,便于人们记忆 。

然而,因特网上的路由器和主机在网络层进行寻址和通信时,并不直接使用域名,而是使用IP 地址 (IP Address)(例如 42.83.144.13) 。IP 地址是分配给网络接口的数字标识符,便于机器处理和路由。

这就产生了一个矛盾——人类喜欢的易记域名与机器需要的数字 IP 地址之间需要一个转换机制。

DNS 的基本概念

域名系统 (Domain Name System, DNS) 的主要作用就是将域名解析(转换)为对应的 IP 地址

DNS 就像是因特网的“电话簿”。你想找某个网站(知道它的域名,像人名),DNS 就能帮你查到它的 IP 地址(像电话号码),然后你的计算机才能真正连接到它。

解析过程简化示意:

  • 用户在浏览器输入域名 cnnic.net.cn 。

  • 主机会先检查自己的本地 DNS 缓存中是否有该域名的记录 。

  • 如果缓存中没有,主机会向配置好的 DNS 服务器发送一个 DNS 查询请求:“cnnic.net.cn 对应的 IP 地址是什么?” 。

  • DNS 服务器在其域名数据库中查找,找到对应的 IP 地址 42.83.144.13 。

  • DNS 服务器将查询结果(IP 地址)返回给用户主机 。

  • 用户主机收到 IP 地址后,就可以使用这个 IP 地址与目标 Web 服务器建立连接并访问网站了 。

这里有一个问题: DNS 可以是单台服务器吗?这会面临以下的问题:

  • 单点故障与性能瓶颈: 理论上可以将所有域名和 IP 地址的映射关系都存在一台巨大的 DNS 服务器上。但这在实践中是不可行的 。
  • 可靠性差: 一旦这台服务器出现故障,整个因特网的域名解析服务就会瘫痪 。
  • 性能瓶颈: 全世界的域名查询请求都涌向一台服务器,它肯定会因超负荷而无法正常工作 。
  • 距离延迟: 用户可能离这台服务器非常远,查询延迟会很高。

因此, 一般来说, DNS 是分布式的系统, 由全球成千上万台 DNS 服务器协同工作来完成域名解析任务。

因特网自 1983 年起就采用了层次结构的命名树(域名结构)和分布式的域名系统 。

  • 高可用性: 即使单个 DNS 服务器故障,也不会影响整个系统的运行 。
  • 高效率: 大多数域名解析可以在本地(或附近的)DNS 服务器完成,只有少量解析需要跨网络通信 。
  • 负载均衡: 查询请求被分散到全球各地的不同服务器上。

因特网的域名结构

因特网采用了层次树状结构 (Hierarchical Tree Structure) 来组织域名 。

结构组成: - 域名由若干个分量组成,分量之间用点. 隔开 。 - 最右边的分量级别最高,称为顶级域名 (Top-Level Domain, TLD) 。 - 向左依次是二级域名 (Second-Level Domain, SLD)、三级域名,等等 。 - 级别最低的域名(通常表示具体主机或服务)写在最左边

命名规则

  • 每一级域名都由英文字母和数字组成 。
  • 每一级域名长度不超过 63 个字符 。
  • 不区分大小写字母
  • 完整的域名总长度不超过 255 个字符 。

管理: - 各级域名由其上一级的域名管理机构管理 。 - 最高的顶级域名ICANN (因特网名称与数字地址分配机构) 进行管理 。

域名示例:zuits.zju.edu.cn - .cn:顶级域名,表示中国 。 - .edu:二级域名(在 .cn 下注册),表示教育机构 。 - .zju:三级域名(在 .edu.cn 下注册),表示浙江大学 。 - zuits:四级域名(由浙江大学自行管理),表示信息技术中心。

顶级域名 (TLD) 的分类

  • 国家顶级域名 (nTLD / ccTLD): 采用 ISO 3166 的国家代码标准。例如:.cn (中国), .us (美国), .uk (英国), .jp (日本) 。
    • nTLD 下的二级域名由该国家自行确定规则(例如,日本用 .ac 表示教育机构,.co 表示公司,而非 .edu 和 .com) 。
  • 通用顶级域名 (gTLD): 不具有国家属性。常见的有:.com (公司企业), .net (网络服务机构), .org (非营利性组织), .edu (美国教育机构), .gov (美国政府部门), .mil (美国军事部门), .int (国际组织) 。
    • 近年来新增了很多 gTLD,如 .app, .shop, .xyz 等。
  • 反向域 (Infrastructure TLD):只有一个.arpa,用于反向域名解析(即从 IP 地址查询对应的域名) 。

中国域名体系: 我国在 .cn 顶级域名下,将二级域名划分为两类 :

  • 类别域名: .ac (科研), .com (工商金融), .edu (教育), .gov (政府), .net (网络服务), .mil (军事), .org (非营利) 。
  • 行政区域名: 34 个省、自治区、直辖市的缩写,如 .bj (北京), .sh (上海), .js (江苏) 。

域名空间:整个因特网的域名结构可以看作一棵倒置的树树根在最上方(没有名字),下面是 TLD,再往下是二级、三级域名… 叶节点通常对应具体的主机

这种按等级管理的命名方法便于维护域名的唯一性,也易于设计高效的查询机制 。

alt text

重要提示:域名只是一个逻辑概念,它与计算机所在的物理地点没有必然联系。例如,.com 域名的服务器不一定在美国。

因特网的域名服务器

为了实现分布式层次化的域名系统,因特网上部署了不同类型的域名服务器,各司其职。主要有以下四种类型:

根域名服务器 (Root DNS Server)

  • 层级: 位于 DNS 层次结构的最顶层(树根)。

  • 职责: 它不直接负责将域名解析为 IP 地址。它的核心任务是管理所有顶级域名 (TLD),即它知道所有顶级域名服务器(如负责 .com、.org、.cn 的服务器)的域名和 IP 地址

  • 数量与分布: 全世界名义上只有 13 个不同 IP 地址的根域名服务器(用 A 到 M 命名)。但实际上,每个“根服务器”都是由分布在全球各地的许多服务器组成的集群,利用任播 (Anycast) 技术,使得用户的查询请求会被路由到地理上最近的一个根服务器实例。这大大提高了查询速度和系统的可靠性。

  • 工作方式: 当收到本地域名服务器的查询请求时(例如查询 www.google.com),根服务器会返回负责 .com 域的 TLD 服务器的 IP 地址列表 。

顶级域名服务器 (Top-Level Domain, TLD Server)

  • 层级: 位于根域名服务器之下。

  • 职责: 负责管理在其下注册的所有二级域名 。例如,.com TLD 服务器管理着所有 .com 结尾的域名(如 google.com, example.com)。.cn TLD 服务器管理着所有 .cn 结尾的域名。

  • 工作方式: 当收到本地域名服务器的查询请求时(例如查询 www.google.com),.com TLD 服务器会查找负责 google.com 这个二级域名的权限域名服务器的 IP 地址,并将其返回给本地域名服务器。

权限域名服务器 (Authoritative DNS Server)

  • 层级: 位于 TLD 服务器之下(或更低层级)。
  • 职责: 这是真正存储着 “域名 ↔︎ IP 地址” 权威映射关系的服务器。每个域名(例如 www.google.com)都必须在至少一个权限域名服务器处注册登记。
  • 工作方式: 当收到本地域名服务器关于其管辖区域内某个域名的查询请求时(例如查询 www.google.com),google.com 的权限服务器会直接返回该域名对应的 IP 地址 。它还知道其下级域名服务器的地址(如果有的话)。

本地域名服务器 (Local DNS Server) - 特殊性: 它不属于上述的根 TLD 权限的层次结构 - 角色: 它是主机进行 DNS 查询的“代理”或“第一跳” 。当主机需要解析域名时,它首先将请求发送给本地域名服务器。 - 来源: 通常由用户的因特网服务提供商 (ISP)、大学、公司或机构提供。它离用户地理位置较近。 - 配置: 本地域名服务器的 IP 地址需要手动或通过 DHCP 配置在用户主机的网络设置中。 - 工作方式: 收到主机的查询请求后,本地域名服务器会负责代替主机,在 DNS 层次结构中进行查询(通常是迭代查询,见下文),并将最终结果返回给主机。它还具有缓存功能。

因特网的域名解析过程

主机是如何通过本地域名服务器,并利用上述的服务器层次结构,最终找到域名对应的 IP 地址的呢?主要有两种查询方式:

递归查询 (Recursive Query) - 特点: “你帮我查到底”。查询责任层层委托。 - 过程: 1. 主机向本地域名服务器发起递归查询:“请告诉我 y.abc.com 的 IP 地址”。 2. 本地域名服务器接受委托,向根域名服务器发起递归查询。 3. 根域名服务器接受委托,向 .com 顶级域名服务器发起递归查询。 4. .com 顶级域名服务器接受委托,向 abc.com 的权限域名服务器发起递归查询。 5. abc.com 权限服务器知道 y.abc.com 的 IP 地址,将结果返回给 .com TLD 服务器。 6. 结果沿着委托链逐级返回:.com TLD 本地域名服务器。 7. 本地域名服务器最终将 IP 地址返回给主机。 - 缺点: 对被查询的服务器(尤其是根和 TLD 服务器)负担过重。它们需要代替查询方联系下一级服务器alt text

迭代查询 (Iterative Query) - 特点: “我告诉你下一步该问谁”。查询方自己负责联系下一级服务器。 - 过程: 1. 主机向本地域名服务器发起递归查询(这一步通常还是递归):“请告诉我 y.abc.com 的 IP 地址”。 2. 本地域名服务器开始迭代查询,向根域名服务器发起查询。 3. 根域名服务器不进行委托,它回复:“我不知道,但你应该去问负责 .com 的 TLD 服务器,它们的 IP 地址是 XXX”。 4. 本地域名服务器自己向 .com 顶级域名服务器发起查询。.com TLD 服务器回复:“我不知道,但你应该去问负责 abc.com 的权限服务器,它们的 IP 地址是 YYY”。 5. 本地域名服务器自己向 abc.com 的权限域名服务器发起查询。abc.com 权限服务器回复:“y.abc.com 的 IP 地址是 ZZZ”。 6. 本地域名服务器将最终结果 ZZZ 返回给主机。

  • 优点: 被查询的服务器(根、TLD)负担轻,只需返回下一级线索即可。 alt text

实践中,通常采用混合模式: - 主机 本地域名服务器使用递归查询(主机只管问,本地服务器负责搞定)。 - 本地域名服务器 其他服务器 (根, TLD, 权限): 使用迭代查询(本地服务器自己跑腿,逐级询问)。

传输协议:DNS 查询和响应报文通常使用 UDP 协议进行封装,服务器监听熟知端口号 53。 > 注: 在某些特殊情况下(如响应报文过长超过 UDP 限制,或进行区域传送时),DNS 也会使用 TCP 端口 53。

DNS 缓存与生存时间 (TTL)

DNS 查询(尤其是涉及根、TLD 和权限服务器的迭代查询)可能需要多次网络往返,带来一定的延迟。为了优化这个过程,DNS 系统广泛使用了高速缓存 (Cache) 。

  • 提高域名解析效率: 对于经常访问的域名,可以直接从缓存中获取 IP 地址,大大缩短查询时间 。
  • 减轻上级服务器负荷: 特别是减轻根域名服务器和顶级域名服务器的压力 。如果每个查询都要从根开始,它们将不堪重负。
  • 减少因特网上的 DNS 查询报文数量: 降低整体网络流量 。

DNS 缓存用来存放最近查询过的域名以及与其对应的 IP 地址映射关系。它还会记录是从哪个服务器获得该映射信息的 。

查询流程:

  1. 当 DNS 服务器(尤其是本地域名服务器)或用户主机收到一个域名解析请求时,它会首先检查自己的高速缓存

  2. 缓存命中 (Cache Hit): 如果缓存中存在该域名的有效记录,则直接使用缓存中的 IP 地址进行响应,无需再向其他 DNS 服务器发起查询。

  3. 缓存未命中 (Cache Miss): 如果缓存中没有该域名的记录,或者记录已过期,则按照标准的 DNS 解析流程(递归/迭代查询)去获取 IP 地址 。获取到结果后,将该映射关系存入缓存以备后续使用。

不过, 域名到 IP 地址的映射关系并不是永久不变的 (例如,服务器更换 IP 地址)。如果缓存中的信息一直不更新,就可能导致用户访问到错误的 IP 地址。

这个问题的解决方案是生存时间 (Time-To-Live, TTL)

为了保持缓存内容的正确性,DNS 记录(由权限域名服务器提供)通常会包含一个生存时间 (TTL) 值

DNS 服务器和主机在缓存某条记录时,也会记下它的 TTL 。缓存中的记录会在 TTL 到期后被删除

这样,当下一次再查询该域名时,就会因为缓存未命中而重新向权限服务器获取最新的映射关系。

实际 TTL 由域名的管理者在权限服务器上配置,可以是几分钟到几天不等。

DNS 缓存则存在于 DNS 解析路径的多个环节:

  • 用户主机: 操作系统通常会维护自己的 DNS 缓存 。有些应用程序(如浏览器)也可能有自己的缓存。
  • 本地域名服务器: 这是最主要的缓存地点,服务于大量用户,缓存命中率通常较高 。
  • 中间 DNS 服务器: 在迭代查询过程中,根服务器、TLD 服务器等也可能进行一定程度的缓存(主要是缓存下一级服务器的地址)。

万维网 (WWW)

首先, 万维网和我们之前提到的因特网, 以太网等概念不同, 万维网 (World Wide Web, WWW) 并非某种特殊的计算机网络,而是运行在因特网之上的一个分布式应用

它可以被看作是一个大规模的、联机式的信息储藏所。其核心机制是超链接 (Hyperlink):万维网通过网页之间的超链接,将分布在全球不同网站上的信息(网页)逻辑上连接一张巨大的信息网

万维网的信息载体是网页(Web Page),它是通过HTML(超文本标记语言)编写的文档,通常包含文本、图像、视频等多媒体内容。用户可以通过浏览器访问这些网页,并通过超链接在不同网页之间导航。

而说到浏览器, 它是用户访问万维网的主要工具。浏览器通过HTTP(超文本传输协议)与托管网页的Web 服务器进行通信,获取网页内容并呈现给用户。

浏览器最重要的部分是渲染引擎,也称为浏览器内核。它负责解析网页内容(HTML, CSS, JavaScript 等)并将其显示 (渲染) 在屏幕上。 不同浏览器使用不同的渲染引擎, 例如Chrome和Edge 使用 Blink,Firefox 使用 Gecko,Safari 使用 WebKit等。不同的浏览器内核对网页内容的解析可能存在差异,因此同一个网页在不同内核的浏览器中显示效果可能不同, Web 开发者需要考虑跨浏览器兼容性 。

万维网应用的基本交互过程: 1. 用户输入 URL: 用户在浏览器地址栏输入网站的域名(例如 www.google.com) 。 2. DNS 解析: 浏览器通过 DNS 服务器将域名解析为对应的 IP 地址 。 3. 浏览器发送请求: 浏览器进程 (作为 HTTP 客户端) 向目标万维网服务器发送 HTTP 请求报文。 4. 服务器处理与响应: 万维网服务器进程 (作为 HTTP 服务器) 收到请求后,执行相应操作(如查找文件),然后向浏览器发回 HTTP 响应报文 。 5. 浏览器渲染: 浏览器接收并解析响应报文中的内容(如 HTML 文件),然后将其渲染成用户可见的网页 。

这个看似简单的过程,实际上涉及了 TCP/IP 体系结构中多个层次的协议协同工作,包括应用层的 HTTP, DHCP, DNS;传输层的 TCP;网际层的 IP, ARP;以及网络接口层的数据链路层协议。本章后续将重点介绍 HTTP。

统一资源定位符 (URL)

为了方便、统一地访问分布在世界范围内的各种文档或资源,万维网使用统一资源定位符 (Uniform Resource Locator, URL) 来指明因特网上任何种类资源的位置。

URL 一般由四个部分组成:<协议>://<主机>:<端口>/<路径>

  • <协议> (Protocol): 指明访问该资源所使用的协议。常见的有:

    • http:超文本传输协议。
    • https:安全的超文本传输协议。
    • ftp:文件传输协议。
    • file:本地文件系统。
  • <主机> (Host): 指明存放资源的服务器。可以是域名IP 地址

  • <端口> (Port): 指明服务器上监听请求的端口号

    • 每个协议都有默认端口(例如 HTTP 默认 80 ,HTTPS 默认 443)。
    • 如果 URL 中省略了端口号,浏览器会自动使用该协议的默认端口。
  • <路径> (Path): 指明资源在服务器上的具体位置(类似文件路径)。

    • 例如 /index.htm 指向根目录下的 index.htm 文件。
    • 服务器也是一台主机, 上面也有自己的文件系统。资源路径就是指向该文件系统中的具体文件或目录。

万维网文档

当我们浏览网页时,浏览器实际上是从 Web 服务器获取并解析、渲染一系列文档。这些文档共同构成了我们看到的丰富多彩、交互式的网页。万维网文档主要由以下三种核心技术(语言)组成 :

  1. HTML (HyperText Markup Language) - 超文本标记语言
  • 核心作用: 定义网页的结构和内容 。
  • 如何工作: HTML 使用各种“标签” (Tag) 来标记文本的不同部分,告诉浏览器这部分内容是什么。
    • 例如,<p> 标签表示一个段落,<h1> 标签表示一级标题,<img> 标签表示一张图片,<a> 标签表示一个超链接。
  • 结构: 一个基本的 HTML 文档通常包含 <head>(首部)和 <body>(主体)两大部分 。
    • <head> 部分包含元信息,如网页标题 (<title>) 、引用的外部文件等。
    • <body> 部分包含用户实际看到的网页内容,如文本、图片、链接等 。
  • 本质: HTML 负责网页的骨架和原始素材。
  1. CSS (Cascading Style Sheets) - 层叠样式表
  • 核心作用: 描述网页的样式或外观(从审美的角度)。
  • 解决的问题: 纯 HTML 只能定义结构,无法很好地控制内容的显示效果(如颜色、字体大小、布局等)。CSS 的出现实现了内容与样式的分离。
  • 如何工作: CSS 定义规则 (Rule),指定某个或某些 HTML 元素应该如何显示。
  • 引入方式: CSS 规则可以写在 HTML 文件内部(<style> 标签或 style 属性),但更常见和推荐的方式是写在独立的 .css 文件中,然后在 HTML 文档的 <head> 部分使用 <link> 标签将其引入。
  • 本质: CSS 负责网页的“妆造”和“排版”。
  1. JavaScript (JS)
  • 核心作用: 控制网页的行为,实现交互功能 。
  • 解决的问题: HTML 和 CSS 主要负责静态内容的展示。如果希望网页能够响应用户的操作(如点击按钮、输入内容)、动态地修改页面内容、与服务器进行异步通信等,就需要 JavaScript。
  • 如何工作: JavaScript 是一种脚本语言,可以在浏览器中运行。它可以:
    • 操作 HTML 元素: 改变元素的样式、内容、属性等。
    • 响应用户事件: 如鼠标点击、键盘输入、页面加载等。
    • 与服务器通信: 在不刷新整个页面的情况下,向服务器发送请求并更新部分页面内容 (AJAX)。
  • 引入方式: JavaScript 代码可以写在 HTML 文件内部(<script> 标签),但更常见和推荐的方式是写在独立的 .js 文件中,然后在 HTML 文档的 <head><body> 末尾使用 <script src="..."> 标签将其引入 。
  • 本质: JavaScript 负责网页的“动作”和“智能”。

HTML、CSS 和 JavaScript 是构建现代网页的三大基石 。它们各自负责不同的层面:HTML 构建结构和内容,CSS 美化样式和布局,JavaScript 实现交互和动态行为。浏览器内核的工作就是将这三者结合起来,解析并渲染出用户最终看到的完整网页。这些文档(静态页面或由服务器后端程序动态生成)都需要通过 HTTP 协议从服务器传输到用户的浏览器。

超文本传输协议 (HTTP)

HTTP 定义了浏览器 (Web 客户端) 如何向 Web 服务器请求万维网文档(如 HTML, CSS, JS 文件, 图片等),以及服务器如何将这些文档传送给浏览器 。

基本流程:

  1. 建立 TCP 连接: 浏览器进程(HTTP 客户进程)首先需要与 Web 服务器进程(HTTP 服务器进程)建立一条 TCP 连接 。Web 服务器通常监听熟知端口号 80 。
  2. 发送 HTTP 请求报文: TCP 连接建立后,浏览器通过该连接向服务器发送一个 HTTP 请求报文 。
  3. 服务器处理请求: Web 服务器收到请求报文后,执行相应的操作(如查找请求的文件)。
  4. 发送 HTTP 响应报文: 服务器通过同一条 TCP 连接向浏览器发回一个 HTTP 响应报文 。
  5. (可能)释放 TCP 连接: 根据 HTTP 版本的不同,TCP 连接可能会在此之后关闭,也可能保持打开以供后续请求使用。

HTTP 的连接方式

非持续连接方式 (Non-Persistent Connection) - HTTP/1.0

  • 工作模式: 每次浏览器要请求一个文件(例如一个 HTML 文件,或该 HTML 文件引用的一个图片),都需要与服务器建立一个新的 TCP 连接 。当收到对该文件的响应后TCP 连接立即关闭

  • 时间开销:

    • 建立 TCP 连接需要 1 个 RTT (往返时间)。
    • 发送 HTTP 请求并等待响应需要 1 个 RTT。
    • 因此,请求一个文档至少需要 2 RTT 的开销,再加上文档本身的传输时延 。
  • 缺点: 如果一个网页包含多个对象(HTML 文件 + 10 张图片),则需要建立 11 次 TCP 连接,产生 22 RTT 的开销,效率非常低。虽然浏览器可以通过建立多个并行 TCP 连接来缓解时延,但这会大量占用服务器资源 。 alt text 持续连接方式 (Persistent Connection) - HTTP/1.1

  • 工作模式: 万维网服务器在发送响应后仍然保持 TCP 连接打开 。同一个客户(浏览器)和服务器可以在这条已建立的连接上继续传送后续的 HTTP 请求和响应报文。这不仅限于同一个页面上的对象,只要是访问同一个服务器上的资源即可 。

  • 流水线 (Pipelining): HTTP/1.1 的持续连接还可以使用流水线方式进一步提高效率 。浏览器可以在收到前一个响应之前,就连续发送多个 HTTP 请求报文 。服务器收到这些请求后,再依次发回对应的响应报文 。

  • 优点: 极大地减少了建立 TCP 连接所需的 RTT 开销和服务器负担,提高了文档下载效率 。

HTTP 的报文格式

HTTP 是面向文本的协议,其报文中的每个字段都是 ASCII 码串,并且字段长度不确定 。报文由组成,每行以回车换行 (CRLF) 结束 。 alt text HTTP 请求报文 (Request Message) 由以下几部分组成:

  • 请求行 (Request Line):方法 URL 版本 CRLF

    • 方法 (Method):指明对资源的操作,如 GET, POST 等 。
    • URL:请求的资源标识符, 简写形式(不含协议和主机部分)即可,如 /index.htm
    • 版本 (Version):使用的 HTTP 版本,如 HTTP/1.1 。
  • 首部行 (Header Lines): 首部字段名: 值 CRLF。可以有零个或多个, 用于传递附加信息,例如,告知服务器浏览器类型、请求的主机名、连接方式等 。

  • 空行 (Empty Line): 一个 CRLF 。标志着首部行的结束。

  • 实体主体 (Entity Body): 实际要传输的数据(例如 POST 方法提交的表单数据)。对于 GET 请求,通常不用 。

alt text 请求行示例: GET /index.htm HTTP/1.1。 首部行示例:

  • Host: www.hnust.cn:指明请求的服务器域名。
  • Connection: close:告知服务器发送响应后关闭 TCP 连接(非持续连接)。
  • User-Agent: Mozilla/5.0:告知服务器浏览器的类型和版本。
  • Accept-Language: cn:告知服务器用户希望优先接收中文版本的文档。

请求行的常见方法: - GET:请求获取 URL 标识的资源。 - HEAD:请求资源的首部信息(与 GET 类似,但响应中没有主体)。 - POST:向服务器提交数据(如表单)。 - PUT:在指定 URL 处存储一个文档(上传)。 - DELETE:删除 URL 标识的资源。

alt text HTTP 响应报文 (Response Message) 的格式如下:

  • 状态行 (Status Line): 版本 状态码 短语 CRLF

    • 版本 (Version):HTTP 版本,如 HTTP/1.1 。
    • 状态码 (Status Code):三位数字,表示请求处理的结果。常见状态码包括:
      • 200:请求成功。
      • 301:资源永久移动(重定向)。
      • 404:未找到资源。
      • 500:服务器内部错误。
    • 短语 (Reason Phrase):对状态码的简短文本描述。
  • 首部行 (Header Lines): 与请求报文类似,首部字段名: 值 CRLF 。

  • 空行 (Empty Line): 一个 CRLF 。

  • 实体主体 (Entity Body): 实际返回的资源内容(如 HTML 文档、图片数据)。有些响应(如 HEAD 请求的响应,或某些错误响应)可能没有主体 。

状态码分类: - 1xx:信息性,表示请求已接收,继续处理 。 - 2xx:成功,表示请求已被成功接收、理解、接受 。如 200 OK, 202 Accepted。 - 3xx:重定向,需要后续操作才能完成请求 。如 301 Moved Permanently, 304 Not Modified。 - 4xx:客户端错误,表示请求包含语法错误或无法完成 。如 400 Bad Request, 404 Not Found。 - 5xx:服务器错误,表示服务器在处理请求的过程中发生了错误 。如 500 Internal Server Error, 503 Service Unavailable。

下面是一些状态行示例: - HTTP/1.1 400 Bad Request:请求有语法错误 。 - HTTP/1.1 404 Not Found:服务器找不到请求的资源 。 - HTTP/1.1 500 Internal Server Error:服务器内部错误 。 - HTTP/1.1 503 Service Unavailable:服务不可用 。

不过, 浏览器通常不会直接显示状态码,而是以更友好的方式(如特定的错误页面)告知用户。例如,看到“找不到页面”通常对应 404 状态码 。

HTTPS

HTTPS (HyperText Transfer Protocol Secure) 是 HTTP 的安全版本,它通过在 HTTP 之上添加一层加密机制来保护数据传输的安全性。 HTTPS 使用 SSL/TLS (安全套接字层/传输层安全协议) 来实现加密和身份验证。

HTTPS 的TLS 握手过程大致如下: 1. 客户端发起连接: 浏览器向服务器发起 HTTPS 连接请求。 2. 服务器响应并发送证书: 服务器返回其数字证书,包含公钥和身份信息。 3. 客户端验证证书: 浏览器验证服务器证书的合法性(如是否由受信任的 CA 签发,是否过期等)。 4. 生成会话密钥: 浏览器生成一个随机的对称加密密钥,并使用服务器的公钥对其加密后发送给服务器。 5. 服务器解密会话密钥: 服务器使用其私钥解密,获得对称加密密钥。 6. 加密通信开始: 双方使用该对称密钥进行加密通信,确保数据在传输过程中不被窃听或篡改。 7. 连接关闭: 通信结束后,双方关闭连接。

早期的万维网应用主要是用户查看存放在不同服务器上的静态文档。为了简化服务器的设计,HTTP 被设计成一种无状态 (Stateless) 协议

服务器不保存关于过去客户端请求的任何信息。每个 HTTP 请求都被视为一个独立的事务,与之前的任何请求都没有关联。服务器处理完请求并发回响应后,就“忘记”了这个客户端。

但是随着万维网的发展,出现了网上购物、电子商务、社交网络等需要识别用户身份并保持用户状态的应用 。例如购物网站需要记住用户的购物车内容, 社交网站需要记住用户的登录状态, 新闻网站需要根据用户的偏好推送内容。

如果 HTTP 完全无状态,用户每次点击页面或刷新,服务器都会“忘记”他是谁,导致无法实现这些功能(例如,购物车每次都会被清空)。

上述问题的解决方案就是 Cookie - 为无状态的 HTTP 增加状态

Cookie 提供了一种机制,使得 Web 服务器能够“记住”(识别)用户,而无需用户在每个请求中都主动提供身份信息(如反复输入用户名密码) 。

本质: Cookie 是一种对无状态的 HTTP 进行状态化 (Stateful) 的技术 。它允许服务器在客户端(浏览器)存储少量信息,并在后续请求中取回这些信息

基本工作原理

Cookie 的工作涉及浏览器和服务器之间的一系列交互: 1. 首次请求 (浏览器 服务器):当用户的浏览器第一次访问某个 Web 服务器时,它发送一个普通的 HTTP 请求报文。 2. 服务器生成 Cookie 并创建记录 (服务器端):Web 服务器收到请求后,意识到这是一个新用户请求中没有携带 Cookie 信息)。服务器为该用户(浏览器)生成一个唯一的 Cookie 识别码 (Cookie ID)。服务器以此 Cookie ID 作为索引,在其后端数据库中创建一个条目,用来记录该用户访问该网站的各种信息(例如登录状态、购物车内容、偏好设置等)。 3. 服务器发送 Cookie (服务器 浏览器):服务器在发回给浏览器的 HTTP 响应报文中,添加一个特殊的首部行Set-Cookie: xxx,其值就是刚刚生成的那个唯一的 Cookie ID (例如 Set-Cookie: 12345678)。 4. 浏览器存储 Cookie (浏览器端):浏览器收到带有 Set-Cookie: 首部的响应后,会解析出服务器的域名和 Cookie ID。浏览器将这对信息(服务器域名, Cookie ID)存储在本地一个特定的 Cookie 文件或内存中。 5. 后续请求 (浏览器 服务器):当用户再次使用该浏览器访问同一个网站(域名相同)时。浏览器在发送 HTTP 请求报文之前,会自动检查本地 Cookie 文件。它会找到之前存储的、与该域名对应的 Cookie ID (例如 12345678)。浏览器将这个 Cookie ID 放入请求报文的一个首部行Cookie: xxx发送给服务器 (例如 Cookie: 12345678)。 6. 服务器识别用户 (服务器端):Web 服务器收到带有 Cookie: 首部的请求后,提取出其中的 Cookie ID。服务器使用这个 Cookie ID 在其后端数据库中查找对应的记录。 7. 服务器返回个性化内容 (服务器 浏览器):通过 Cookie ID 识别出用户后,服务器就可以获取该用户的状态信息(如登录状态、购物车内容等)。服务器据此生成并返回一个个性化的网页给用户。例如,显示“欢迎回来,用户名!”或展示用户上次加入购物车的商品。

alt text 例如, 当用户在某些网页登录时勾选了“记住我” ,服务器可能会在 Set-Cookie: xxx 响应中为这个 Cookie 设置一个较长的过期时间。这样,即使用户关闭了浏览器甚至重启了电脑,只要 Cookie 文件中的记录没过期,下次访问该网站时浏览器仍会自动发送该 Cookie,服务器就能识别用户,实现自动登录。

万维网缓存与代理服务器

为了提高万维网 (WWW) 的访问效率,减少网络流量和用户感受到的延迟,Web 系统广泛使用了缓存 (Caching) 机制, 这主要体现在两个方面:

  • Web 缓存 (Web Cache)

    • 是一种存储最近访问过的 Web 对象(如 HTML 页面、图片、CSS 文件等)副本的机制 。
    • 位置: 可以位于客户端(例如浏览器自己的缓存),也可以位于网络中的中间系统
  • 代理服务器 (Proxy Server)

    • 位于中间系统上的 Web 缓存,通常服务于一个机构(如校园网、企业网)内的多个用户
    • 作用: 充当用户(浏览器)和原始 Web 服务器之间的中介。

Web 缓存的基本工作原理

Web 缓存(无论是浏览器缓存还是代理服务器)会把最近的一些 HTTP 请求及其对应的响应(包含 Web 对象)暂存在本地存储(如磁盘)中 。

当一个新的 HTTP 请求到达时(例如,浏览器请求一个图片):

  • 浏览器缓存: 浏览器首先检查自己的缓存。
  • 代理服务器: 如果浏览器未缓存配置了使用代理,请求会发往代理服务器,代理服务器检查自己的缓存。

此时有两种可能的情况: - 缓存命中 (Cache Hit): 如果缓存中存在所请求对象的有效副本,缓存(浏览器或代理)就直接将这个副本返回给请求者,无需再向原始 Web 服务器发起请求 。 - 缓存未命中 (Cache Miss): 如果缓存中没有所请求对象的副本,或者副本已失效(见下文),缓存服务器(代理)则会代表请求者,向原始 Web 服务器发起请求,获取该对象。获取到对象后,先将其存入自己的缓存,然后再返回给最初的请求者。

浏览器缓存和代理服务器缓存有点类似一级缓存和二级缓存的关系。浏览器缓存是用户本地的一级缓存,代理服务器缓存是网络中的二级缓存。

alt text

缓存一致性问题

Web 缓存的一个重要挑战是缓存一致性 (Cache Consistency) 问题:如果原始服务器上的文档已经被修改了,但代理服务器(或浏览器)缓存中的副本还是旧版本,用户获取到的将是过期的信息。如何确保缓存副本与原始文档保持一致?

解决方案是 HTTP 缓存验证机制. HTTP 协议通过特定的首部字段来处理缓存一致性问题:

原始服务器在响应中通常会包含:

  • Last-Modified:资源最后修改的时间 。
  • Expires:资源的过期时间(在此时间前,缓存可认为副本是新鲜的) 。
  • ETag:资源的实体标签,用于标识特定版本的资源。
  • Cache-Control:指示缓存机制的指令。

缓存验证流程:

  1. 检查本地副本新鲜度: 当代理服务器收到请求时,先检查缓存中是否有该对象的副本。

    • 副本未过期: 如果副本存在且根据 Expires 字段判断未过期,则直接返回缓存副本给主机 。

    • 副本已过期 (或无 Expires 信息): 如果副本已过期或没有过期信息,代理服务器不能直接返回副本,需要向原始服务器验证 。

  2. 发送条件 GET 请求 (Conditional GET): 代理服务器向原始服务器发送一个特殊的 GET 请求,其中包含一个首部行 If-Modified-Since:,其值就是缓存副本的 Last-Modified 时间 。这个请求的意思是:“请把这个资源发给我,但前提是它在 XXX 时间之后被修改过”。

  3. 原始服务器响应:

    • 未修改 (图 6-51b): 如果原始服务器发现资源自 If-Modified-Since: 指定的时间以来没有被修改过,它就不会发送整个资源内容,而是返回一个状态码为 304 Not Modified 的响应报文(该响应没有实体主体) 。

    • 已修改 (图 6-51c): 如果资源已经被修改,原始服务器会返回一个正常的 200 OK 响应,其中包含更新后的资源内容以及新的 Last-Modified 和 Expires(或其他缓存控制)头 。

  4. 代理服务器处理响应:

    • 收到 304: 代理服务器知道缓存中的副本仍然是有效的。它会更新副本的元数据(如新的 Expires 时间),然后将缓存中的副本返回给主机 。

    • 收到 200: 代理服务器用响应中的新内容更新本地缓存的副本及其元数据,然后将新内容返回给主机 。 alt text

通过这种条件 GET 机制,即使缓存副本过期需要验证,如果资源并未实际更改,也可以避免传输整个资源内容,只需传输一个简短的 304 响应即可,仍然节省了带宽。