一个HTTP请求的曲折经历

📅 发布时间:2026/7/7 12:04:50 👁️ 浏览次数:
一个HTTP请求的曲折经历
引言从一次点击开始这是一个平凡的午后你坐在电脑前打开浏览器在地址栏里输入了一个网址https://www.example.com然后轻轻按下了回车键。就在这一瞬间一个看不见的旅程开始了。你也许以为这只是一个简单的页面加载但实际上一个庞大的数字生态系统被瞬间激活无数设备、协议、算法和代码协同工作只为了将一个网页送到你的眼前。这个旅程充满了曲折和冒险就像一场史诗般的远征。从你按下回车的那一刻一个HTTP请求诞生了它要穿越网络的重重关卡经历各种考验最终带着响应回到你的浏览器。本文将跟随这个请求的脚步详细解剖它的每一个环节让你看到那些隐藏在表象之下的惊心动魄。第一章域名解析的冒险——DNS查询请求的第一站并不是直接奔向目标服务器而是要先找到服务器的IP地址。因为互联网上的设备只认IP不认域名。你输入的www.example.com是一个便于人类记忆的名字但机器需要的是类似93.184.216.34这样的数字地址。这个将域名转换为IP的过程就是DNSDomain Name System域名系统查询。1.1 浏览器缓存——最近的庇护所浏览器首先会检查自己的DNS缓存。毕竟如果你之前访问过这个网站浏览器可能还记得它的IP地址。这就像你出门前先摸摸口袋看看钥匙是否就在身上。如果缓存命中DNS查询立即结束请求直接进入下一阶段。但如果是第一次访问或者缓存已过期浏览器就会继续下一步。1.2 操作系统缓存与hosts文件浏览器会向操作系统发起DNS请求。操作系统也有自己的DNS缓存同时还会检查本地的hosts文件。这是一个古老的文本文件里面可以手动配置域名与IP的映射。如果你曾经为了绕过某些限制而修改过hosts文件那么这里就可能发挥作用。如果操作系统缓存或hosts文件中有记录那么解析成功否则请求会被发送到配置的DNS服务器通常是你的ISP提供的递归DNS服务器。1.3 递归DNS服务器的远征现在请求来到了递归DNS服务器。这个服务器就像一位经验丰富的向导它负责为你找到最终的答案。递归DNS服务器也有自己的缓存。如果它缓存了www.example.com的IP它会立即返回。如果没有它就要开始一次递归查询。递归查询的过程是这样的递归DNS服务器首先向根DNS服务器发送请求。根服务器是DNS体系的顶层全球共有13组根服务器。根服务器不会知道www.example.com的具体IP但它知道负责.com域名的顶级域名服务器TLD Server的地址。递归DNS服务器接着向.com顶级域名服务器发起请求。TLD服务器管理着所有以.com结尾的域名它也不直接知道www.example.com的IP但它知道负责example.com这个域名的权威DNS服务器的地址。最后递归DNS服务器向example.com的权威DNS服务器请求。这个权威服务器是域名所有者配置的它掌握着该域名下所有记录的最终信息。权威服务器返回www.example.com的IP地址。这个过程就像你在问路你问路人甲根他说去问交警TLD交警说去问片警权威片警终于告诉了你具体位置。每一步都可能因为网络延迟而耗费时间但通常都很快。1.4 可能的曲折DNS污染与劫持在这个看似简单的流程中可能发生许多曲折。比如在某些网络环境下DNS查询可能被中间人篡改返回错误的IP地址这就是DNS污染也称为DNS劫持。你可能本来要去example.com却被带到了一个钓鱼网站或者广告页面。为了应对这种情况出现了DNSSECDNS安全扩展技术它通过数字签名来验证DNS响应的真实性但部署并不普遍。另一个曲折是DNS缓存投毒攻击者试图向递归DNS服务器注入错误的记录使得大量用户被导向恶意网站。还有DNS负载均衡同一个域名可能对应多个IPDNS服务器会根据地理位置或服务器负载返回不同的IP以实现流量分配。1.5 从IPv4到IPv6如果网站同时支持IPv6权威DNS服务器可能返回一个AAAA记录IPv6地址。你的操作系统和网络环境需要支持IPv6才能使用它。否则只能退回到IPv4。最终经过一系列查询你的浏览器得到了www.example.com的IP地址比如93.184.216.34。但这只是旅程的开始。第二章TCP连接的建立——三次握手有了IP地址浏览器就可以尝试与服务器建立连接了。HTTP协议除了HTTP/3通常运行在TCP传输控制协议之上而TCP是一个面向连接的、可靠的传输协议。在发送HTTP请求之前必须先建立TCP连接这个过程被称为“三次握手”。2.1 SYN包的出发你的操作系统内核会构造一个TCP SYN包意思是“同步序列号”用于发起连接。这个包包含一个初始序列号ISNInitial Sequence Number是随机生成的用于后续的数据排序和确认。SYN包被封装在IP数据报中通过网卡发送出去开始了前往服务器IP的旅程。2.2 网络的传输这个数据包会经过你的路由器、交换机、光纤穿过城市、国家甚至跨越大洋。沿途的每个路由器都会查看IP头中的目的地址并根据路由表决定下一跳的方向。这个过程可能经过数十个路由器跃点。如果网络拥堵或某条链路中断路由器可能会重新选择路径造成延迟。2.3 服务器端的响应当服务器收到SYN包后如果它正在监听那个端口通常是80或443并且愿意接受连接它会回复一个SYN-ACK包。这个包中ACK部分是对客户端SYN的确认序列号1SYN部分则是服务器自己的初始序列号。2.4 客户端的最后确认客户端收到SYN-ACK后再发送一个ACK包给服务器表示确认收到了服务器的SYN。至此TCP连接建立完成双方可以开始传输数据了。2.5 可能的曲折SYN洪泛与重传三次握手并非总是一帆风顺。如果客户端发送的SYN包在途中丢失了客户端会等待一段时间超时重传时间RTO后重新发送SYN。如果多次重试无果连接就会失败浏览器会显示“无法访问此网站”。另一种常见的曲折是SYN洪泛攻击攻击者发送大量伪造源IP的SYN包服务器为每个SYN分配资源并回复SYN-ACK但永远等不到ACK导致服务器资源耗尽无法处理正常请求。为此操作系统引入了SYN Cookie等防护机制。TCP选项也在握手中协商比如窗口缩放Window Scaling允许更大的数据窗口选择性确认SACK让接收方能告知发送方哪些数据包丢失了这些都能提高传输效率。第三章TLS/SSL的加密握手——如果是HTTPS如今大多数网站都使用HTTPS也就是HTTP over TLS。在TCP连接建立之后TLS握手就会开始目的是在客户端和服务器之间建立一个加密通道。3.1 客户端Hello客户端发送一个ClientHello消息包含它支持的TLS版本、加密套件列表、一个随机数Client Random以及可能的扩展如SNI服务器名称指示用来指定要访问的域名因为一台服务器可能托管多个域名。3.2 服务器Hello与证书服务器收到ClientHello后选择合适的TLS版本和加密套件回复ServerHello包含服务器随机数Server Random。接着服务器发送它的数字证书Certificate证书里包含服务器的公钥、域名、颁发机构等信息。如果需要进行双向认证服务器还可能请求客户端证书CertificateRequest。3.3 证书验证客户端收到证书后要验证证书的合法性证书是否在有效期内证书的域名是否匹配访问的域名证书是否由受信任的CA证书颁发机构签发这需要检查CA的签名而CA的证书又由更高级的CA签名形成一条信任链直到根证书。根证书被预置在操作系统或浏览器中。是否被吊销可以通过CRL证书吊销列表或OCSP在线证书状态协议检查。如果验证失败浏览器会显示安全警告用户可以选择忽略风险行为或中止连接。这是常见的曲折之一证书过期、自签名证书、或证书被吊销都会导致用户无法正常访问。3.4 密钥交换验证通过后客户端生成一个随机数Pre-Master Secret用服务器的公钥加密后发送给服务器ClientKeyExchange。服务器用私钥解密得到Pre-Master Secret。然后双方使用Client Random、Server Random和Pre-Master Secret通过伪随机函数生成主密钥Master Secret再从中派生出会话密钥用于后续的对称加密。3.5 结束握手客户端发送ChangeCipherSpec表示后续通信将加密并发送EncryptedHandshakeMessage对之前所有握手消息的摘要供服务器验证。服务器同样发送ChangeCipherSpec和EncryptedHandshakeMessage。握手完成之后的应用数据HTTP请求都将被加密传输。3.6 可能的曲折会话复用如果之前连接过同一个服务器客户端可以使用会话ID或会话票据Session Ticket来恢复之前的会话跳过证书验证和密钥交换直接进入加密通信这叫做“会话复用”能显著提高性能。但会话票据可能被破解或过期导致复用失败。TLS 1.3进一步简化了握手将往返次数减少到1次甚至0-RTT但也带来了一些安全考量。第四章HTTP请求的发送现在加密通道已经建立如果是HTTP则直接发送浏览器终于可以发送HTTP请求了。请求由三部分组成请求行、请求头、请求体。4.1 请求行请求行包括方法GET、POST等、路径/index.html、HTTP版本HTTP/1.1或HTTP/2。例如GET /index.html HTTP/1.14.2 请求头请求头包含大量元信息比如Host: www.example.com必需因为一台服务器可能托管多个域名User-Agent浏览器标识Accept客户端能接受的响应类型如text/htmlAccept-Encoding支持的压缩算法gzip, deflate, brCookie携带之前服务器设置的会话信息Connection: keep-alive希望保持连接以便复用以及缓存相关的头If-Modified-Since, If-None-Match等4.3 请求体对于GET请求通常没有请求体。POST、PUT等方法会携带数据如表单提交或JSON。4.4 HTTP/2与HTTP/3的变革如果使用HTTP/2请求会被二进制分帧同一个TCP连接上可以并发多个流多路复用避免了HTTP/1.1的队头阻塞问题。HTTP/2还支持头部压缩HPACK减少冗余。HTTP/3更进一步放弃了TCP改用基于UDP的QUIC协议它内置了加密、多路复用、更快的连接建立0-RTT以及更好的拥塞控制能有效应对丢包。4.5 可能的曲折队头阻塞在HTTP/1.1中如果使用持久连接默认是管线化pipelining允许连续发送多个请求而不必等待响应但响应必须按顺序返回。如果第一个响应很慢后面的响应即使已经准备好也要等待这就是队头阻塞Head-of-line blocking。实际中浏览器通常为每个域名打开多个TCP连接通常6个来缓解但仍有瓶颈。HTTP/2通过多路复用解决了这个问题。4.6 代理与网关请求可能会经过代理服务器。浏览器可能配置了代理或者网络出口处有透明代理。代理可以缓存内容、过滤请求、或转发到目标服务器。如果代理是正向代理它会代表客户端向目标服务器发送请求如果是反向代理它则代表服务器接收请求将在第六章详述。第五章网络传输的波折HTTP请求被封装成TCP段再交给IP层打包成数据报最后通过链路层如以太网发送出去。这一段旅程充满了不确定性。5.1 数据包的分割与MTU以太网帧通常最大传输单元MTU是1500字节。如果IP包加上TCP头超过1500就需要进行IP分片。但现代网络通常使用路径MTU发现找到整个路径上的最小MTU避免分片。分片会增加丢失风险因为一片丢失整个包都要重传。5.2 路由与IPIP协议负责将数据包从源主机送到目的主机它不保证可靠性只管尽力而为。沿途每个路由器都会检查IP头修改TTL生存时间字段每经过一个路由TTL减1减到0时包被丢弃并发送ICMP超时消息给源。TTL防止包无限循环。5.3 NAT穿透如果你的设备在局域网内使用私有IP如192.168.x.x那么在出网关时路由器会执行网络地址转换NAT将私有IP和端口映射为公网IP和端口并记录映射表。当响应回来时路由器再根据映射表转回内网设备。NAT可能造成一些问题比如P2P连接需要打洞。5.4 拥塞控制与丢包TCP有拥塞控制机制根据网络状况动态调整发送速度。如果发生丢包TCP会认为网络拥塞减小发送窗口并重传丢失的包。重传有两种超时重传RTO超时和快速重传收到三个重复ACK。丢包会导致延迟增加甚至引发TCP的慢启动大幅降低传输速度。5.5 防火墙与IDS数据包可能经过防火墙或入侵检测系统IDS。防火墙根据规则允许或阻止包。如果请求被防火墙误判为恶意可能被直接丢弃导致连接超时。IDS则可能记录日志或报警。5.6 CDN的介入如果网站使用了CDN内容分发网络DNS解析可能直接返回CDN节点的IP而不是源站IP。这样请求就被导向离用户最近的CDN节点。CDN节点可能缓存了内容直接返回响应从而大大缩短路径。但CDN也可能带来曲折比如节点故障、缓存未命中、或配置错误导致回源失败。第六章到达服务器——反向代理与负载均衡请求终于到达了目标服务器但通常它不会直接面对应用服务器。大型网站往往部署了反向代理服务器如Nginx、HAProxy和负载均衡器。6.1 反向代理的作用反向代理位于服务器端对外表现为一台服务器实际上将请求转发给内部的多台应用服务器。它的好处包括负载均衡分发请求到不同服务器均衡负载。缓存缓存静态内容或动态页面减轻后端压力。安全隐藏后端服务器结构过滤恶意请求。SSL终结处理HTTPS加解密后端使用HTTP通信。压缩对响应进行gzip压缩。6.2 负载均衡算法负载均衡器有多种算法轮询Round Robin依次分配。最少连接Least Connections分配给当前连接数最少的服务器。IP哈希IP Hash根据客户端IP计算哈希保证同一客户端始终访问同一台服务器会话保持。加权轮询根据服务器性能分配权重。6.3 可能的曲折服务器宕机与健康检查如果某台后端服务器宕机负载均衡器应能通过健康检查定期发送心跳请求发现并自动剔除避免请求被转发到故障机器。但如果健康检查配置不当或者故障发生得突然请求仍可能被发送到故障服务器导致502 Bad Gateway错误。6.4 缓存命中如果反向代理开启了缓存并且请求的URL匹配缓存规则那么代理可能直接从缓存中返回响应而不需要转发给后端。常见的缓存头如Cache-Control: max-age3600告诉代理可以缓存1小时。但缓存也可能带来问题比如缓存了过期的内容用户看到的是旧页面。6.5 Rewrite规则在反向代理层还可能进行URL重写例如将/article/123重写为/index.php?id123以便后端框架处理。重写规则错误可能导致404。第七章应用服务器的处理请求最终到达了应用服务器比如运行着JavaTomcat、PythonDjango、Node.js、PHPFPM等的机器。这里才是真正的业务逻辑处理的地方。7.1 Web服务器容器应用服务器通常与Web服务器容器集成。例如Nginx通过FastCGI协议与PHP-FPM通信将请求转发给PHP进程。Node.js本身可以作为HTTP服务器但通常前面也有Nginx做反向代理。7.2 路由分发应用框架如Spring MVC、Express、Django根据请求的URL和方法将请求分发到对应的控制器Controller或处理函数。这个过程可能涉及路由匹配、中间件过滤等。7.3 中间件的洗礼请求在到达最终处理函数之前会经过一系列中间件Middleware。中间件可以执行多种任务身份验证检查用户是否登录是否有权限。日志记录记录请求信息。跨域处理CORS添加响应头允许跨域。请求解析解析JSON、表单数据。限流限制IP的请求频率。如果中间件检测到问题如未认证它可能直接返回响应如401终止后续流程。这是可能的曲折例如Session过期导致重定向到登录页。7.4 业务逻辑处理这是核心部分。控制器可能会调用服务层、模型层处理业务逻辑。例如对于一个电商网站请求可能是“查看商品详情”那么它会从数据库中读取商品信息进行格式化然后返回HTML或JSON。7.5 会话管理Web应用通常需要跟踪用户状态比如购物车内容。这通过会话Session实现通常基于Cookie中的Session ID。服务器端Session可以存储在内存、数据库或分布式缓存如Redis中。如果用户请求没有携带有效的Session ID服务器可能会创建一个新的会话。如果使用了分布式部署会话管理需要特别注意用户的请求可能被负载均衡到不同服务器如果Session存储在单机内存中就会丢失。解决方案是使用粘性会话同一用户始终分配到同一服务器或集中式存储如Redis。7.6 可能的曲折异常与超时业务逻辑处理过程中可能抛出异常比如空指针、数据库连接失败等。如果未妥善处理服务器可能会返回500 Internal Server Error。此外如果处理时间过长超过了应用服务器或反向代理的超时设置请求也会被中断返回504 Gateway Timeout。第八章与数据库的交互许多HTTP请求需要从数据库获取数据或写入数据。这一步往往是性能瓶颈所在。8.1 连接池应用服务器通常不会为每个请求创建一个新的数据库连接因为建立连接开销大。而是使用连接池预先创建一批连接请求时从池中借用用后归还。连接池大小需要合理配置太小会导致请求等待连接太大会耗尽数据库资源。8.2 SQL查询的旅程应用构建SQL语句或通过ORM生成然后通过数据库驱动发送给数据库服务器。数据库服务器进行语法解析、优化、执行最后返回结果集。8.3 索引与慢查询如果查询没有使用索引或者表数据量巨大查询可能会非常慢导致请求响应时间变长甚至拖垮数据库。这就是为什么需要数据库优化和慢查询日志。一个曲折的例子是由于数据量增长原本高效的查询变成了慢查询导致页面加载缓慢。8.4 事务与锁对于写操作可能涉及事务ACID。事务保证了数据的一致性。但事务可能引发锁竞争比如两个事务互相等待对方释放锁造成死锁。数据库会自动检测并回滚其中一个事务但应用需要处理重试。8.5 缓存层为了减轻数据库压力应用通常会引入缓存如Redis或Memcached。请求先查询缓存如果命中直接返回否则查询数据库并将结果写入缓存。缓存策略需要考虑数据一致性、过期时间、缓存穿透、缓存雪崩等问题。缓存穿透查询一个不存在的数据缓存和数据库都没有导致请求每次都打到数据库。可以用布隆过滤器解决。缓存雪崩大量缓存同时过期导致请求全部涌向数据库。可以设置随机过期时间。缓存击穿一个热点key过期高并发访问直接打到数据库。可以用互斥锁或永不过期策略。8.6 读写分离与分库分表对于大型应用数据库可能采用主从复制写操作在主库读操作在从库。应用需要根据业务决定使用哪个数据源。进一步地当单表数据量巨大可能需要分库分表水平拆分这增加了复杂性查询可能需路由到特定分片。第九章响应的生成与返回业务逻辑处理完毕应用服务器生成HTTP响应。响应包括状态行、响应头、响应体。9.1 状态码状态码表示请求的结果200 OK成功。301/302重定向Location头指示新地址。304 Not Modified用于缓存表示资源未变客户端可用缓存。400 Bad Request客户端请求错误。401 Unauthorized未认证。403 Forbidden禁止访问。404 Not Found资源不存在。500 Internal Server Error服务器内部错误。502 Bad Gateway网关错误。503 Service Unavailable服务不可用。9.2 响应头响应头包含Content-Type如text/html; charsetutf-8Content-Length响应体长度Set-Cookie设置CookieCache-Control缓存指令Location重定向地址Access-Control-Allow-OriginCORS头等等9.3 响应体响应体是实际内容可能是HTML、JSON、XML、图片等。对于动态页面内容是生成的对于静态文件可能是从文件系统读取的。9.4 可能的曲折304与缓存如果客户端发送了条件请求头如If-Modified-Since服务器可以检查资源是否有更新。若无更新返回304 Not Modified不包含响应体浏览器从缓存加载。这样可以节省带宽。9.5 压缩为了减小传输体积服务器可以对响应体进行压缩如gzip、brotli。需要在响应头中注明Content-Encoding: gzip。如果客户端不支持压缩但现代浏览器都支持则不能压缩。第十章响应的回程响应从应用服务器出发沿着来时的路径返回客户端。但途中可能经历一些变化。10.1 反向代理的再次介入响应先回到反向代理。反向代理可以缓存响应如果响应头允许缓存代理可以将响应存入缓存下次相同请求直接返回。压缩如果之前没压缩代理可以压缩。添加/修改头如添加X-Proxy-Cache: HIT表示缓存命中。10.2 CDN的缓存如果使用了CDN响应可能被CDN节点缓存。CDN节点可以根据缓存策略决定是否缓存。当其他用户请求相同资源时直接从CDN返回加速访问。但这也可能导致内容更新不及时需要主动刷新或设置合理的缓存过期时间。10.3 网络传输的再次冒险响应包再次穿越网络经历路由、可能的重传、拥塞控制等。如果网络状况不好大文件传输可能分片、丢包重传导致下载缓慢。10.4 客户端接收客户端的网卡接收到数据包操作系统内核重组TCP段交给浏览器。浏览器开始解析响应。第十一章浏览器的渲染当浏览器收到HTTP响应后它的工作才刚刚开始。它需要解析HTML、CSS、JavaScript最终将页面绘制在屏幕上。11.1 解析HTML浏览器收到HTML内容后会进行解析构建DOM树。解析过程是逐步的浏览器可以边接收边解析。如果遇到外部资源如link、script、img浏览器会发起新的HTTP请求来获取这些资源。这些子请求又会重复整个流程但通常它们会复用已经建立的TCP连接如果支持keep-alive或者同时打开多个连接。11.2 预加载扫描器现代浏览器有一个预加载扫描器它在解析HTML的同时扫描其中的资源链接并提前发起请求从而加快页面加载。11.3 CSSOM构建CSS资源被解析为CSSOMCSS对象模型它与DOM树结合形成渲染树。CSS解析会阻塞渲染因为浏览器需要知道所有样式才能正确绘制。11.4 JavaScript执行JavaScript脚本可能会阻塞HTML解析因为脚本可能使用document.write修改文档。所以浏览器遇到script标签时通常会暂停DOM解析下载并执行脚本然后再继续。async和defer属性可以改变这一行为实现异步加载。11.5 样式计算与布局有了DOM树和CSSOM浏览器计算每个元素的最终样式然后进行布局reflow计算每个元素在屏幕上的位置和大小。11.6 绘制与合成布局完成后浏览器将每个元素绘制到不同的图层上然后合成composite成最终图像显示在屏幕上。绘制可能涉及光栅化、GPU加速等。11.7 可能的曲折阻塞渲染如果某个JavaScript脚本执行时间过长或者CSS文件过大会导致页面长时间空白影响用户体验。这就是为什么通常将CSS放在头部JS放在底部或使用异步。另外如果网络请求失败某些资源无法加载可能导致页面显示异常如图片缺失、样式错乱。11.8 交互与后续请求页面加载完成后用户可能开始交互点击按钮触发新的HTTP请求Ajax。这些请求同样会经历类似的过程但可能只更新部分页面SPA单页应用。WebSocket可以建立持久连接实现双向通信。第十二章请求的最终归宿当页面完全呈现在你眼前这个HTTP请求的使命似乎结束了。但它的影响远未停止。12.1 连接的管理浏览器可能会保持TCP连接一段时间keep-alive以便复用。服务器端也有超时设置。连接最终会被关闭通过四次挥手但如果很快又有新请求可能再次复用。12.2 缓存的留存响应可能被浏览器缓存、代理缓存、CDN缓存。下一次请求相同的URL可能直接从缓存获取连网络都不用出。12.3 日志与监控服务器记录了这次请求的日志包括时间、IP、状态码、耗时等。这些日志用于监控、分析、故障排查。如果请求出错开发人员可以从日志中追溯。12.4 用户行为的追踪请求可能携带跟踪参数用于分析用户行为。比如广告点击、页面停留时间等。这些数据被收集并用于优化。12.5 安全审计一些请求可能触发安全警报比如SQL注入尝试、XSS攻击等。WAFWeb应用防火墙会记录并阻止恶意请求。