从敲下回车到看见页面,这一路上实际执行了三个处理:DNS 的域名解析、HTTP 请求、HTTP 响应。 它们不是并列的三件事,而是一条接力链——每一棒的产出正好是下一棒的投入:域名解析把"名字"换成"IP 地址"(解决"发给谁"),HTTP 请求把"我要什么"写成一张纸递过去(解决"要什么"),HTTP 响应把东西连同说明一起送回来(解决"给什么")。链上还有三处会"拐弯":缓存命中让链条提前结束、301/302 重定向让整条链再走一遍、CDN / 反向代理让解析出来的 IP 根本不是源服务器。而这条链最重要的一条性质是:它不是一条直线,而是"主线 + N 次循环"——DNS 解析、建连接、谈加密通常只做一次,请求—响应的来回却要做很多次(页面里每个 CSS、JS、图片、字体都算一个)。搞清这条链,就同时得到两样东西:"网页是怎么打开的"的完整答案,以及"哪一步断了该查哪儿"的排查地图。
这一节是第四章的"收口节"——把前面十一节拆开的零件,按运行时序拼成一条完整的链。
- 4.4 的 URL、4.5 的请求、4.6 的响应:就是本节第二、三棒的详细展开
- 4.7 的 Cookie、4.8/4.9 的代理、4.10 的 Web 应用:全都是这条链上的"附加剧情"
- 3.21/3.22 的 DNS、3.18 的 TCP、3.17 的端口、3.7 的 IP:本节第一棒和"建连接"那一段讲的正是它们
- 4.11 问的是"要访问它,你得备好什么"(静态的准备清单);本节问的是"访问的时候,实际执行了什么"(动态的运行过程)。两节合起来,才是"打开一个网页"的完整回答
一、这一节到底在问什么
第四章开篇那句问话是"我们真的知道每天浏览的 Web 网站是如何工作的吗"。从 4.1 一路走到 4.11,零件基本齐了。这一节把它们装起来,回答最后一个问题:
从敲下回车,到页面上出现内容,这段时间里到底执行了哪些处理?
教材把答案收成三段:
| 处理 | 它解决什么 | 一句话说清 |
|---|---|---|
| DNS 的域名解析 | 发给谁 | 把"名字"翻译成"IP 地址" |
| HTTP 请求 | 要什么 | 把"要哪一份东西"写成一张纸递过去 |
| HTTP 响应 | 给什么 | 把东西连同"它是什么"的说明一起送回来 |
因为一次访问必须依次解决三个问题,而且解决顺序不能颠倒:不知道对方在哪台机器(第一段没完成),就无从发请求(第二段开始不了);没有请求递过去,也就没有响应回来(第三段无从谈起)。
二、三个处理,三段接力
三段的关系不是"三件并列的事",而是一条交接清楚的接力链:
第一棒 第二棒 第三棒
DNS 域名解析 ──→ HTTP 请求 ──→ HTTP 响应
拿到:一串域名 拿到:IP + 路径 拿到:请求报文
给出:一个 IP 地址 给出:一张请求报文 给出:状态码 + 头部 + 正文
(3.21 · 3.22) (4.4 · 4.5) (4.5 · 4.6)
每一棒的"给出",正是下一棒的"拿到"。 这句话听起来像废话,但它有一个很实际的推论:
任何一棒断了,后面全都不会发生。 —— 解析不出来,就建不了连接;连不上,就发不出请求;请求没送出去,就不会有响应。
而且三棒里,只有第一棒(DNS 解析)通常只做一次,第二、三棒要来回很多遍——这一点后面第六节会讲清。
三、第一棒:DNS 的域名解析
1. 为什么不能跳过这一步
收 3.21 讲过,DNS 是"网络的电话簿":人记域名,机器认 IP 地址。
麻烦就在这里——你在地址栏里敲的是 shop.example.com,但数据真正要发到某个 IP 地址上。中间这层"翻译"就是第一棒要干的活。而干这活的,是浏览器里那个 DNS 解析模块(收 3.22)。
2. 它不是"问一次就完了"——有缓存层次
这一层是本节值得补上的:同一件事要按顺序往下找,找到就停。
| 顺序 | 查哪儿 | 命中就意味着 |
|---|---|---|
| ① | 浏览器自己的 DNS 缓存 | 刚才访问过这个站,直接用 |
| ② | 操作系统的 DNS 缓存 / hosts 文件 | 本机记着,直接用 |
| ③ | 配置好的 DNS 服务器(路由器、运营商、8.8.8.8、114.114.114.114) | 它替你去递归查询,结果按 TTL 缓存 |
| ④ | 一级级往上问:根 → 顶级域 → 权威服务器 | 拿到最终答案 |
第③层的缓存能存多久,由那条记录的 TTL 决定(收 3.22 的资源记录)。TTL 没到,再来问就直接给你上一次的答案——这就是"第一棒通常不用真的往外跑"的原因。
3. 解析结果不是固定的
一个值得记住的事实:同一个域名,不同时间、不同地点、不同网络,解析出来的 IP 可能不一样。
原因不是出错,而是有意设计:CDN 与就近接入,正是靠"让不同地区的用户解析到离自己最近的那台缓存节点"来加速的(收 4.8 讲的反向代理)。所以你解析出来的那个 IP,很可能根本不是源服务器。
4. 这一棒的产出
一个 IP 地址。 拿到它,第一棒的任务就完成了,交接给第二棒。
四、第二棒:HTTP 请求
1. 严格说,发请求之前还有两小步
拿到 IP 之后不能直接开口说话,得先把"路"接上:
这两小步合起来,就是"准备工作"里那六步的第④⑤步。它们是第二棒的前置动作,也是"贵的部分"——后面会看到,这两步同样通常只做一次。
2. 请求报文本身:三段结构
收 4.5 讲过的规矩,这里只强调两处最容易忘的:
- 起始行里只有路径,没有域名:
GET /index.html HTTP/1.1 - 域名在
Host头里:Host: shop.example.com
收 4.4 那句结论在这里兑现:服务器永远只看到"路径 + 查询串"。 你在地址栏里敲的六段,到这一棒只剩两段装进了那张纸。
3. 浏览器替你塞进去的一堆东西
这一条很值钱:你什么都没写,但那张纸上已经贴满了标签。
| 头 | 谁塞的 | 干什么用 |
|---|---|---|
Host |
浏览器 | 告诉服务器要访问哪个网站(同一台机器上可能跑着很多个站) |
User-Agent |
浏览器 | 说明"我是谁",服务器据此返回不同版本 |
Accept / Accept-Encoding |
浏览器 | 说明"我能收哪些格式、支不支持压缩" |
Cookie |
浏览器自动翻出来带上 | 收 4.7:这张纸条是它自己记着的 |
If-None-Match |
浏览器 | 收 4.6:协商缓存,问服务器"我手上这份还新吗" |
Referer |
浏览器 | 说明"我是从哪个页面跳过来的" |
因为你只写了地址,剩下的全是浏览器按规矩替你补的。这也解释了为什么"手动拼一个请求"很难完全模拟浏览器——缺了某些头,服务器给的东西会不一样。
4. 一个页面不止一个请求
收 4.1 讲过的:HTML 里每个 CSS、JS、图片都只是引用,各要单独要一回。
所以第二棒和第三棒会反复来回——这才是"几十上百次请求"的真实来源(后面第六节展开)。
5. 这一棒的产出
一张请求报文,交到服务器手上。
五、第三棒:HTTP 响应
服务器那边接过请求之后做的事,收 4.6 讲得很细,这里按"这一棒"的视角收一遍:
服务器执行四步:收下请求 → 找到内容(静态读文件 / 动态跑程序)→ 装好包装 → 发出响应。
响应报文也是三段(状态行 + 头部 + 空行 + 正文),其中三样最关键:
| 三样东西 | 回答什么问题 |
|---|---|
| 状态码 | 结果如何?(4 开头怪自己,5 开头怪服务器——收 4.5) |
Content-Type |
这是什么?「类型/子类型」直接决定浏览器怎么处理 |
Content-Length / Transfer-Encoding |
有多长、怎么读(定长还是分块) |
一个容易忽略的点:响应里装的不一定是网页
同一套 HTTP,运的东西五花八门:
| 正文是什么 | 谁消费它 |
|---|---|
| HTML | 渲染引擎(画成页面) |
| CSS / JS | 渲染引擎与脚本引擎 |
| 图片 / 字体 | 渲染引擎(当资源用) |
| JSON | 脚本(不是给人看的) —— 收 4.10 |
| 纯数据 / 文件 | 下载下来,或交给别的程序 |
判断依据永远是那个 Content-Type 头,不是文件后缀,也不是"看起来像什么"。
这一棒的产出
一段字节流 + 一份说明,交给浏览器渲染引擎。到这里,三个处理都完成了——但一次访问往往到这里才刚过半。
六、串成一条线:一次访问的完整时序
把三段接起来,从敲回车到看见页面:
| # | 发生了什么 | 收哪一节 |
|---|---|---|
| 1 | 你在地址栏敲下地址,回车 | — |
| 2 | 拆 URL:协议 / 主机 / 端口 / 路径 | 4.4 |
| 3 | 查缓存:本地存过这份吗?还新鲜吗?新鲜就直接用,整条链到此结束 | 4.6 |
| 4 | DNS 解析:域名 → IP 地址(第一棒) | 3.22 |
| 5 | 建 TCP 连接:和那个 IP 的端口三次握手 | 3.18 |
| 6 | 谈 TLS(https 才有):验证证书、商定密钥 | 4.11 |
| 7 | 发 HTTP 请求(第二棒) | 4.5 |
| 8 | 服务器处理:找内容 → 装包装 → 发出 | 4.6 |
| 9 | 回 HTTP 响应(第三棒) | 4.5 |
| 10 | 浏览器渲染:解析成树 → 应用样式 → 画出来 | 4.2 / 4.3 |
| 11 | 发现页面里还有别的资源(CSS、JS、图片……)→ 回到第 7 步再来一遍,循环 N 次 | 4.1 |
| 12 | 全部到齐,页面才算完整 | — |
它不是一条直线,而是"主线 + N 次循环"。
第 4、5、6 步(DNS 解析、建连接、谈加密)——通常只做一次,因为解析出的 IP 和建好的连接会被复用。第 7~9 步(请求 → 处理 → 响应)——要做很多次,页面里每个资源各一回。
这就是"几十个请求却还不慢"的真正原因:贵的部分只做一次,便宜的部分做很多次。如果你觉得页面慢,往往就是因为这几步里某一步被重复做了(比如每次请求都重新建连接)。
七、三个会"拐弯"的地方
上面那条链画得太顺了。实际跑起来,有三处会让它拐个弯——这也是本节最容易漏掉的细节。
1. 缓存命中:链条提前结束
第 3 步查缓存强缓存命中时,整条链连第一棒都不做,直接从本地拿出来显示(收 4.6)。
这就是"第二次打开同一个页面特别快"的原因——不是网变快了,是活儿根本没那么干了。
2. 301 / 302 重定向:整条链再走一遍
收到的响应不是内容,而是一句"东西搬家了,去 Location 里那个地址拿"(收 4.5 的状态码家族)。
浏览器会拿着新地址重新走一遍——建连接、发请求、收响应,如果换了域名还要重新做一次 DNS 解析。
所以 F12 里会看到多出来一轮请求。这不是重复,是规矩要求它再走一遍。
3. CDN / 反向代理:解析出来的 IP 根本不是源服务器
第 4 步解析得到的那个 IP,可能只是离你最近的缓存节点(收 4.8)。你拿到的内容可能是它替你取回来的、甚至是它早就存好的。
所以"同一个域名,不同人解析到不同 IP"不是异常——这正是大型网站让全世界都访问得快的方式。
还有一种"拐弯":响应里还藏着子资源
第 11 步那个循环,本质上也是"拐弯":一个响应里可以再引出好几个请求。CSS 里引字体、JS 里调接口、页面里嵌图片——层层套下去,所以页面是"一点点长出来"的(收 4.10 讲的 Web 应用,还会让这个过程变得更频繁)。
八、三段失败,三种现象
这条链有一个非常实际的用法:哪一棒断了,现象是不一样的。
| 断在哪一段 | 你看到的现象 | 该先查什么 |
|---|---|---|
| DNS 解析 | "找不到服务器"/ DNS 相关报错 | 域名拼错没、DNS 服务器设置、hosts 文件 |
| 建连接 | "无法访问此网站"、连接超时 | 网络通不通、端口、防火墙、代理设置残留 |
| 请求 → 响应 | 有回应但内容不对:404 / 403 / 500 | 看状态码第一位:4 怪自己,5 怪服务器 |
| 渲染 / 子资源 | 页面出来了,但样式乱、图缺 | F12 里看具体哪个资源失败了 |
4.11 那张表是按"客户端模块"分的(缓存、Cookie、代理、扩展);这张表是按"三个处理"分的(解析、连接、请求响应)。同一件事的两个切法——排障时哪个顺手用哪个。
一条最实用的经验:"页面本身打不开"和"页面开了但缺东西",是完全不同的问题。 前者断在前两棒,后者只是某个子资源自己没拿到——页面是好的。
九、动手:Demo49 把三段分开看
不靠"感觉",而是把三个处理一段一段地单独拎出来看,并且亲手验证"第一棒通常只做一次"。
第 1 步|只看第一棒。 命令行敲:
nslookup example.com
得到一个 IP 地址——这就是第一棒的产出。
第 2 步|换个 DNS 服务器再问一次。
nslookup example.com 8.8.8.8
对比两次结果。不一样是正常的——第一棒的结果可以被有意设计。
第 3 步|看 DNS 缓存。
ipconfig /displaydns
你会看到一长串"刚查过的域名 + TTL 倒计时"。这就是"第一棒通常只做一次"的证据——本机记着答案,短期内不用再问。
第 4 步|只看第二、三棒。
curl -v http://example.com/
> 开头的那几行是请求报文(第二棒),< 开头的那几行是响应报文(第三棒)。一条命令,两棒分得清清楚楚。
第 5 步|只取响应头部。
curl -I https://example.com/
这就是第三棒的前半段——状态码和头部,正文不要。
第 6 步|让"第一棒失败"长什么样。 把域名换成一个不存在的:
curl -v http://no-such-host-abcxyz.com/
报的是解析失败,而不是连接失败——因为第一棒就没过去,第二棒压根没开始。这一步是本节的核心现场。
第 7 步|F12 计时栏对时序。 刷新一次页面,看"计时"那一栏的分段:
排队 → DNS 查找 → 连接 → TLS → 等待 → 下载
这六段正好对应上面时序的第 3~9 步。哪段长,问题就在哪段。
第 8 步|30 秒实验。 数一下这一次访问一共发了多少个请求。回头再看 4.1 那句"几十上百次请求"——现在你能自己解释了:因为第 7~9 步被循环了 N 次。
十、常见误区
- "DNS 解析每次访问都要做一遍。" —— 有多层缓存(浏览器 → 系统 → DNS 服务器),同一个域名的解析结果通常被缓存复用。一次访问里往往只做一次,TTL 决定多久后要重新问。
- "一个网页只发一个 HTTP 请求。" —— 主页 + 每个 CSS、JS、图片、字体各一次。第二、三棒要反复来回。
- "域名解析出来的 IP 是固定的。" —— 不同时间、地点、网络可以解析到不同 IP。CDN 与就近接入正是靠这个工作的。
- "请求和响应是同一件事的两面,可以合并理解。" —— 它们是两方各自执行的处理:请求是浏览器写的,响应是服务器写的。方向、内容、负责人都不同。
- "访问慢就是网速慢。" —— 慢可能出在任何一段:DNS 慢、握手慢、服务器慢(等待耗时长)、文件大(下载慢)。必须按段看。
- "URL 里写了域名,所以服务器知道我在访问哪个域名。" —— 服务器是从
Host头知道的;请求行里只有路径和查询串(收 4.4)。 - "响应里一定是网页。" —— 可能是 HTML、CSS、JS、JSON、图片、字体……
Content-Type说了算(收 4.6)。 - "收到 200 就说明页面对了。" —— 200 只说明这一个请求被正确处理。页面里某张图 404,主页照样是 200。
- "DNS 解析成功就说明网络是通的。" —— 解析成功只说明问到了 DNS 服务器。后面的建连接、谈加密、发请求都可能失败。
- "重定向只是换个地址而已。" —— 301/302 会让浏览器从建连接那一步重新来过(换域名时还要重做 DNS 解析)。一次访问变成两轮。
十一、动手自测
- 本节标题点名的三个处理分别是哪三个?各自解决什么问题?
- 为什么说这三棒是"接力"关系?
- DNS 解析要依次查哪几层?哪一层决定"多久之后要重新问"?
- 为什么同一个域名在不同时间能解析出不同的 IP?
- 发出 HTTP 请求之前,还要先完成哪两件事?
- 请求报文里为什么没有域名?服务器怎么知道你要访问哪个站?
- 一次访问里,DNS 解析通常做几次?请求—响应来回几次?为什么?
- 响应里有哪些东西决定"浏览器拿到之后怎么处理"?
- 响应是 301/302 时会发生什么?
- "页面打不开"和"页面开了但某张图没出来",分别断在哪一段?
答案:
① DNS 的域名解析(从域名找到 IP——解决"发给谁")、HTTP 请求(告诉服务器要什么——解决"要什么")、HTTP 响应(服务器把东西送回来——解决"给什么")。② 因为每一棒的产出正好是下一棒的投入:解析出 IP 才能建连接,连上了才能发请求,请求递进去才有响应出来。任何一棒断了,后面全都不会发生。 ③ 依次查:浏览器自己的 DNS 缓存 → 操作系统的缓存 / hosts 文件 → 配置的 DNS 服务器(它替你递归查询)→ 根 / 顶级域 / 权威服务器。DNS 服务器上那条记录的 TTL 决定它缓存多久、多久后重新问。④ 因为结果可以被有意设计:CDN 与就近接入让不同地区的用户解析到离自己最近的节点,负载均衡也会让同一域名解析到不同服务器。⑤ 先建 TCP 连接(三次握手,收 3.18);如果网址是 https,还要先谈好 TLS(收 4.11)。⑥ 因为同一台服务器上可以跑很多个网站,光靠 IP 分不出来。域名写在 Host 头里,服务器靠它判断你要访问哪个站(收 4.4)。⑦ DNS 解析通常只做一次——解析出的 IP 会被缓存复用;请求—响应的来回通常做很多次——页面里每个 CSS、JS、图片、字体都要各要一回。这就是"几十上百次请求却还不慢"的原因:贵的部分(解析、连接、加密)只做一次,便宜的部分(一次请求)做很多次。 ⑧ 状态码(结果如何)、Content-Type(「类型/子类型」决定浏览器怎么处理)、Content-Length 或 Transfer-Encoding(有多长、怎么读)。另外 Cache-Control / ETag 决定下次还要不要重新下(收 4.6)。⑨ 浏览器不显示这份内容,而是拿着 Location 头里的新地址重新走一遍整条链(换域名时还要重新做 DNS 解析)。所以 F12 里会看到多出来一轮请求。⑩ "打不开":断在前两棒——先看 DNS 解析(域名能不能解析出 IP),再看建连接(能不能连上)。"开了但某张图没出来":页面本身是好的,断在那个图片资源自己的请求上(F12 里能看到它是 404 还是超时)。
十二、下一步学什么
- ☑ 5.1 在同一网络中传输数据(以太网、无线局域网(Wi-Fi)) ✅ 已学 —— 在同一网络中传输数据(以太网、无线局域网(Wi-Fi))(第五章开篇章:本节链路上的时序第 4 步"建连接"往下走,就是第五章要讲的"最后那一段路"——两条路的判据〔同网段走交换机、不同网段交给默认网关〕、以太网与 Wi-Fi 是同一层的两副肉身、介质共用引出 CSMA/CD 与 CSMA/CA 两套规矩、数据帧与"交换机只看门牌")
- ☐ 5.2(按教材顺序) —— 报个标题接着走:第五章讲的是"同一网络内部怎么送数据";下一节大概率是以太网的传输机制(帧的格式、MAC 地址与交换机转发的细节)、无线局域网的机制(CSMA/CA、信道、AP 与 SSID),或交换机的作用与转发原理。等你报标题。
相关笔记
- 浏览Web网站时的准备工作(访问Web时使用的应用软件与协议) —— 上一节:访问前的静态准备清单;本节讲访问时实际执行了什么
- 网络的电话簿(域名解析、主机名、DNS) —— 第一棒的理论来源:"网络的电话簿"
- 使用DNS自动获取IP地址(资源记录、DNS解析模块、递归查询) —— 第一棒的机制:解析模块、递归查询、资源记录与 TTL
- 对应用程序的数据进行可靠传输(TCP) —— 时序第 5 步的三次握手
- 根据端口号分配数据到应用程序(端口号、已知端口号) —— 连接要连到"对的端口",80 与 443 的区别
- 数据的发送和接收(IP、IP数据包、路由) —— 拿到 IP 之后,数据包怎么一站站接力到那儿
- Web网站的地址(URL) —— 时序第 2 步"拆 URL";也是"服务器只看到路径 + 查询串"的出处
- 请求Web网站的文件(HTTP) —— 第二、三棒的报文结构与状态码家族
- 传输Web网站的文件(HTTP响应) —— 服务器那四步;缓存与 304 让链条提前结束
- 记录Web网站的文件(HTTPCookie) —— 请求头上那条
Cookie是谁自动带上的 - 对Web网站的访问进行代理(代理服务器) —— CDN 与反向代理为什么让解析出的 IP 不是源服务器
- Web浏览器不仅仅是用来浏览网页的(Web应用) —— 响应里那些 JSON 是给脚本吃的;Web 应用让"循环"更频繁
- Web网站是如何构建的(Web网站) —— "一次打开网页从来不是一次请求",本节给出了机制上的解释
- 网络的网络(互联网) —— 这一整条链,就是"互联网上跑一次 Web 访问"的具体样子
- 在同一网络中传输数据(以太网、无线局域网(Wi-Fi)) —— 下一章:时序里"建连接"之后,数据真正走的最后那一段路,由以太网与 Wi-Fi 完成