输入 URL 后发生了什么:从浏览器到服务器的一次完整请求
按浏览器解析 URL、DNS 查询、TCP 连接、HTTP 请求、服务器响应和页面渲染的顺序,讲清楚一次网页访问的完整链路。
相关工具
这道题为什么适合作为网络开篇
“在浏览器输入 URL 并按下回车之后会发生什么”,是计算机网络里很典型的入口题。它看起来只是在问一次网页访问,实际会把 DNS、HTTP、HTTPS、TCP、IP、缓存、状态码、浏览器渲染和连接关闭都串起来。文中的网络章节也是从这道题开始讲,因为它能把零散概念放回一条真实链路里。
如果只背结论,很容易变成一串名词:DNS、三次握手、HTTP 请求、服务器响应、浏览器渲染。问题是,名词之间怎么接上,谁先发生,谁依赖谁,出了问题该往哪一层看,就不清楚了。网络学习最怕的不是概念多,而是概念没有顺序。
这一篇先不展开每个细节。DNS 递归查询、HTTP 缓存、HTTPS 握手、TCP 三次握手和四次挥手,后面都可以单独讲。这里先把主线走通:浏览器拿到一个 URL 后,怎样一步一步把它变成能在网线上传输的数据,又怎样把服务器返回的内容变成你看到的页面。

一次网页访问可以先按这条主线记:解析、查询、连接、请求、响应、渲染。
第一步:浏览器先解析 URL
URL 不是一个普通字符串,它里面藏着浏览器发请求所需的基本信息。浏览器拿到 URL 后,会先拆出协议、主机、端口、路径等部分。比如 `https://example.com/docs/index.html` 中,`https` 表示协议,`example.com` 是主机名,`/docs/index.html` 是要访问的路径。如果 URL 没写具体路径,通常会访问站点默认文件,比如 `/index.html`。
解析 URL 的意义,是让浏览器知道这次请求要找谁、用什么协议、访问服务器上的哪个资源。文中把 URL 解释成请求服务器里的文件资源,这个说法很适合新手理解:你不是在访问一个抽象的网站,而是在向某台服务器请求某个资源,只是这个资源可能是一份 HTML,也可能是图片、CSS、JavaScript 或接口返回的 JSON。
这一步还会牵出缓存。浏览器在真正发请求前,可能会先看本地缓存是否可用。如果强缓存命中,就不一定去服务器拿资源;如果需要协商缓存,就会向服务器确认资源有没有变化。缓存机制后面单独讲,这里先记住:输入 URL 后,不是每次都会完整访问服务器。
第二步:生成 HTTP 请求报文
URL 解析完,浏览器就能构造 HTTP 请求。请求报文里会有请求方法、请求路径、协议版本、请求头,必要时还会有请求体。比如访问页面通常是 GET,请求表单提交或接口写入数据时可能是 POST。
请求头里会带很多上下文信息,例如浏览器能接受什么类型的内容、是否带 Cookie、是否使用缓存验证字段、当前页面从哪里跳来。分析请求问题时,经常不能只看 URL,还要看请求方法、请求头和请求体。方法不对、Content-Type 不对、Cookie 没带上,都可能让服务器返回完全不同的结果。
这也是为什么站内有 HTTP 状态码、请求头解析、请求排查这类工具。网络问题落到真实排查时,第一步往往不是背协议,而是把请求报文看清楚。
第三步:DNS 把域名变成 IP
浏览器知道要访问 `example.com`,但操作系统发送网络包时需要的是 IP 地址。域名方便人记,IP 地址方便机器定位。DNS 要做的事,就是把域名解析成对应的 IP。
文中说,在把 HTTP 消息交给操作系统发送之前,必须先查询服务器域名对应的 IP 地址。DNS 服务器保存了域名和 IP 的对应关系,但它不是一台万能服务器。真实查询会涉及本地缓存、本地 DNS、根域 DNS、顶级域 DNS、权威 DNS 等层级。后面的 DNS 文章会展开递归查询和迭代查询。
这一层常见的问题包括:域名解析错了,DNS 缓存没更新,本地网络使用了异常 DNS,或者 CDN 调度到了不合适的节点。你能 ping 通 IP,不代表域名解析一定正常;域名能解析,也不代表后面的 TCP 和 HTTP 一定正常。
第四步:浏览器把发送任务交给协议栈
拿到 IP 后,浏览器不会自己操作网卡。它会调用 Socket 库,把发送任务交给操作系统里的协议栈。文中对协议栈的描述很直观:上面的部分会向下面的部分委托工作,下面的部分收到委托后继续处理。
协议栈上半部分主要是 TCP 和 UDP,它们负责收发数据。HTTP 通常基于 TCP,HTTP/3 则基于 UDP 上的 QUIC。再往下是 IP,负责网络包收发和路由选择。IP 旁边还有 ICMP 和 ARP:ICMP 用来传递错误和控制信息,ARP 用来根据 IP 找到对应的 MAC 地址。最下面是网卡驱动和网卡,负责把数据变成物理链路上的信号。
这条分层关系很重要。应用层只关心“我要发什么请求”,TCP 关心可靠传输,IP 关心发到哪个地址,网卡关心怎么在链路上传。出了问题时,也可以按这条线往下查。

浏览器不是直接把数据扔到网线上,而是逐层委托操作系统协议栈处理。
第五步:TCP 先建立连接,再传数据
HTTP 基于 TCP 传输时,客户端和服务器要先建立 TCP 连接。常说的三次握手,本质上是确认双方都有发送和接收能力。客户端发 SYN,服务端回 SYN 和 ACK,客户端再回 ACK。双方状态都进入 ESTABLISHED 后,连接才算建立。
文中还提到,TCP 连接不是一根真实的线,而是双方计算机里维护的一组状态。这个理解很关键。所谓连接建立、连接断开,其实是双方通过报文和状态变化达成一致。Linux 上可以用 `netstat -napt` 这类命令查看 TCP 连接状态。
如果 HTTP 请求比较长,超过 MSS,TCP 不会一口气把所有数据塞进一个包里,而是按 MSS 拆成多块。每块数据都会加上 TCP 头,再交给 IP 层。TCP 头里有源端口、目标端口、序号、确认号、状态位、窗口大小等字段,用来处理应用定位、乱序、丢包、流量控制和拥塞控制。
第六步:HTTP 数据被一层层加上头部
浏览器生成的 HTTP 请求,到了 TCP 层会加 TCP 头,到了 IP 层会加 IP 头,到了链路层还会加 MAC 头。可以把这个过程理解成寄快递:HTTP 是包裹内容,TCP 头写端口和序号,IP 头写源 IP 和目标 IP,MAC 头负责当前链路上的下一跳。
IP 头里需要源 IP 和目标 IP。目标 IP 来自 DNS 解析结果;源 IP 则由系统根据网卡和路由表选择。如果电脑有多个网卡,比如有线、无线、虚拟网卡,系统会按路由规则决定从哪块网卡发出去。Linux 上可以用 `route -n` 查看路由表。
协议号也会写进 IP 头。文中提到,HTTP 经过 TCP 传输时,IP 包头的协议号会填写为 `06`,表示上层协议是 TCP。这样对方收到 IP 包后,才知道应该把数据交给 TCP 模块继续处理。

每往下一层,都会补上本层需要的头部信息;接收时再反过来逐层拆开。
第七步:服务器处理请求并返回响应
网络包到达服务器后,会按相反方向拆开:链路层去掉 MAC 头,IP 层确认目标地址和协议号,TCP 层根据端口把数据交给对应应用,最后 Web 服务器拿到 HTTP 请求。服务器再把请求交给对应的处理程序,比如静态文件服务、后端接口、模板渲染或网关转发。
服务器返回的 HTTP 响应通常包含状态码、响应头和响应体。状态码告诉浏览器这次请求的大致结果,比如 200 表示成功,301/302 表示重定向,304 表示资源未修改,404 表示找不到,500 表示服务内部错误。响应头可能包含压缩方式、缓存策略、Cookie、内容类型等信息。响应体则是页面 HTML、图片、脚本、接口 JSON 等具体内容。
所以排查网页打不开时,要分清楚问题发生在哪一段。DNS 没解析到 IP、TCP 连接失败、TLS 证书异常、HTTP 返回 404、接口返回 500,这些看起来都是“打不开”,处理方向完全不同。
第八步:浏览器渲染页面,最后关闭连接
浏览器拿到响应后,会解析 HTML,继续加载 CSS、JavaScript、图片、字体等资源。每一个资源都可能触发新的请求,只是连接可能被复用。浏览器一侧还会继续关心 DOM、CSSOM、布局、绘制、回流和重绘,这些属于浏览器渲染链路,后面可以单独展开。
请求结束后,连接不一定立刻断开。HTTP Keep-Alive 会让连接在一段时间内复用,避免每个资源都重新建立 TCP 连接。如果需要关闭 TCP 连接,通常会走四次挥手。四次挥手之所以要分多步,是因为 TCP 是双全工协议,双方的发送方向和接收方向要分别关闭。
到这里,一次 URL 请求的主线就完整了:浏览器解析 URL,生成 HTTP 请求;DNS 找到 IP;操作系统协议栈通过 TCP、IP、网卡把数据发出去;服务器处理并返回 HTTP 响应;浏览器解析响应并渲染页面。后面学习网络,每个专题都可以放回这条链路里理解。
常见问题
输入 URL 后一定会发生 DNS 查询吗?
不一定。如果浏览器、操作系统或本地 DNS 缓存里已经有结果,可能直接使用缓存。缓存失效或没有命中时,才需要继续查询。
HTTP 请求一定要先建立 TCP 连接吗?
常见的 HTTP/1.1 和 HTTP/2 基于 TCP,需要先建立 TCP 连接。HTTP/3 基于 QUIC,底层使用 UDP,但 QUIC 自己实现了连接管理和可靠传输能力。
为什么同一个页面会发很多次请求?
HTML 只是页面入口。浏览器解析 HTML 后,还会继续请求 CSS、JavaScript、图片、字体和接口数据,所以打开一个页面通常不是一次请求,而是一组请求。