读《图解HTTP》代理、网关、隧道与缓存到底是什么本文是阅读《图解HTTP》第 5 章后的学习整理结合个人理解做了少量补充。文中的流程图和表格用于概括本章概念不使用原书截图也不替代原书内容。这篇文章解决什么问题我们平时访问一个网站时直觉上会以为浏览器直接连到了目标服务器。实际情况往往更复杂请求可能先经过代理服务器也可能经过网关、隧道、缓存服务器最后才到达真正保存资源的服务器。这一章主要讨论的就是这些与 HTTP 协作的 Web 服务器组件一台服务器如何承载多个网站虚拟主机HTTP 请求在中途可能遇到哪些角色代理、网关、隧道为什么缓存能减少访问源服务器的次数缓存服务器和客户端缓存分别是什么一台服务器为什么能放多个网站虚拟主机HTTP/1.1 允许一台 HTTP 服务器搭建多个 Web 站点。物理上可能只有一台服务器但使用虚拟主机功能后表面上可以像多台服务器一样分别承载不同域名的网站。问题在于多个域名经过 DNS 解析后可能指向同一个 IP 地址。当请求到达服务器时服务器需要知道客户端到底想访问哪个域名下的网站。这个判断依赖 HTTP 请求中的Host首部。GET /index.html HTTP/1.1 Host: blog.example.com可以把虚拟主机的访问过程理解成这样域名 ADNS 解析到同一台服务器域名 BHTTP 请求携带 Host 首部服务器根据 Host 区分目标网站所以虚拟主机的核心不是“一台机器真的变成了多台机器”而是服务器根据请求里的Host首部把同一个 IP 上的不同域名区分开。HTTP 请求路上的中间角色HTTP 通信时除了客户端和服务器还可能存在一些用于转发通信数据的应用程序。书中重点介绍了三类代理、网关、隧道。它们都可以把请求转发给通信线路上的下一站服务器也可以接收下一站服务器返回的响应再转发给客户端。代理替客户端转发请求代理是一种有转发功能的应用程序扮演客户端和服务器之间的“中间人”角色。它的基本行为是请求不改变请求 URI转发请求响应响应客户端代理服务器源服务器持有资源实体的服务器被称为源服务器。代理从客户端接收请求后会把请求转发给前方持有资源的目标服务器源服务器返回的响应也会先经过代理再传给客户端。在 HTTP 通信中可以级联多台代理服务器。每次通过代理转发请求或响应时需要追加Via首部用来标记经过的主机信息。客户端代理 proxy1代理 proxy2源服务器使用代理服务器的理由包括利用缓存减少网络带宽流量在组织内部针对特定 URI 进行访问控制获取访问日志书中还按两个维度给代理分类分类维度类型含义是否使用缓存缓存代理转发响应时预先保存资源副本再次收到相同资源请求时可直接返回缓存是否修改报文透明代理转发请求或响应时不对报文做任何加工是否修改报文非透明代理转发请求或响应时会对报文内容进行加工网关让 HTTP 连接到非 HTTP 服务网关和代理的工作机制很相似也会转发其他服务器的通信数据。不同的是网关能让通信线路上的服务器提供非 HTTP 协议服务。对客户端来说网关有时就像自己拥有资源的源服务器一样处理请求客户端未必能察觉通信目标其实是网关。转换为非 HTTP 协议通信处理结果HTTP 响应客户端 HTTP 请求网关非 HTTP 服务器/后端系统书中举到的例子包括网关连接数据库使用 SQL 语句查询数据Web 购物网站通过网关和信用卡结算系统联动网关还能提高通信的安全性例如在客户端与网关之间的通信线路上加密以确保连接安全。隧道建立一条安全通信线路隧道是在相隔较远的客户端和服务器之间进行中转并保持双方通信连接的应用程序。它的目的是按要求建立一条与其他服务器的通信线路并使用 SSL 等加密手段进行通信确保客户端能与服务器安全通信。通过隧道建立安全通信线路客户端隧道服务器隧道本身不会解析 HTTP 请求而是把请求保持原样中转给之后的服务器。通信双方断开连接时隧道也会结束。代理、网关、隧道的区别这三个概念容易混在一起可以用下面这张表快速区分概念书中核心描述典型作用代理 Proxy位于客户端和服务器之间接收客户端请求并转发给源服务器再把响应转发给客户端缓存、访问控制、访问日志网关 Gateway转发其他服务器的通信数据让服务器提供非 HTTP 协议服务连接数据库、连接信用卡结算系统、提高通信安全性隧道 Tunnel在客户端和服务器之间中转并保持通信连接本身不解析 HTTP 请求使用 SSL 等加密手段建立安全通信线路一句话记忆代理偏“转发”网关偏“转换”隧道偏“透明传输”。缓存为什么能让 Web 更快缓存是指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可以减少对源服务器的访问从而节省通信流量和通信时间。缓存服务器属于代理服务器的一种也就是缓存代理。缓存服务器的基本工作方式可以概括为没有缓存已有缓存有效需要确认或已失效客户端请求资源缓存服务器内是否已有资源副本向源服务器请求资源转发响应时复制资源并保存返回给客户端缓存是否仍然有效向源服务器确认有效性必要时重新获取新资源缓存的优势在于如果某个资源已经被缓存客户端就可以从缓存服务器获取资源源服务器也不必反复处理相同请求。但缓存并不是只要存在就一定能直接使用。书中强调即使缓存服务器中有缓存也可能因为客户端要求、缓存有效期、源服务器资源更新等因素需要向源服务器确认资源的有效性。若判断缓存失效缓存服务器会再次从源服务器获取新资源。客户端也有缓存缓存不仅可以存在于缓存服务器内也可以存在于客户端浏览器中。浏览器缓存如果有效就不必再向服务器请求相同资源可以直接从本地磁盘读取。和缓存服务器一样当浏览器判断缓存过期后也会向源服务器确认资源有效性如果缓存已经失效就会再次请求新资源。补充理解缓存相关首部要到后面一起看第 5 章主要讲“缓存是什么、缓存服务器和客户端缓存怎么工作”。具体的缓存控制细节会在 HTTP 首部相关内容里展开。实际排查缓存问题时常见会关注这些字段Cache-ControlExpiresETagLast-ModifiedAge其中no-cache和no-store很容易混淆no-cache不是“完全不缓存”而是“使用缓存前需要确认有效性”真正不保存内容的是no-store。实践用 curl 观察 Host、代理和缓存首部下面是结合开发场景的补充实践不是原书中的命令示例。1. 通过 Host 首部模拟访问虚拟主机curl -H Host: www.example.com http://192.168.1.100/ curl -H Host: blog.example.com http://192.168.1.100/同一个 IP 地址可以因为Host不同而路由到不同站点。2. 通过 HTTP 代理发送请求curl -x http://proxy.example.com:8080 -v http://www.example.com/如果链路中存在代理可以重点观察是否出现Via等字段。3. 查看缓存相关响应首部curl -I https://www.example.com/ \ | grep -i cache-control\|expires\|etag\|last-modified\|age常见需要关注的字段包括Cache-ControlExpiresETagLast-ModifiedAge