从一次 URL 输入说起 ——《网络是怎样连接的》第一章读后感

0 阅读7分钟

前言:那个老生常谈的面试题

"从你在浏览器输入一个 URL,到页面显示出来,中间发生了什么?"

这道题我被问过不下十次,也背过不下十个版本的答案。但说实话,每次答完我都隐约感觉自己是在背八股,而不是真的理解了什么。

直到最近拿起这本户根勤写的《网络是怎样连接的》,第一章就把我拉到一个"哦,原来如此"的清醒状态。这本书的切入角度很妙——它不是枯燥地讲协议定义,而是追着一个数据包,从浏览器出发,一路旅行到服务器,让你亲眼看清楚每一个环节到底发生了什么。


第一章就聚焦在这趟旅程的起点:浏览器

一、URL:一个地址,藏着很多信息

万事的起点是那一串我们天天打的网址,学名叫 URL(Uniform Resource Locator,统一资源定位符)

我们平时觉得网址不就是个字符串嘛,但书里一拆解,发现它其实是一份"指令书":

www.example.com/dir/page.ht…

 ↑          ↑              ↑

协议类型   服务器名称       资源路径

协议类型告诉浏览器:"用什么方式去取东西"——http:// 就是用 HTTP 协议去 Web 服务器拿,ftp:// 就是用 FTP 协议去文件服务器拿,file:// 则是直接读本地文件。

服务器名称是目标地址(后面 DNS 会把它翻译成 IP 地址)。

资源路径是你要哪个文件。如果路径末尾是 / 或者没有写文件名,Web 服务器通常会默认返回 index.html

一个小细节:URL 里省略了端口号,是因为 HTTP 有默认端口 80、HTTPS 是 443,浏览器会自动补上。这就好比你打电话给公司总机,不需要说分机号,总机会转给默认部门。


二、HTTP 请求:浏览器在"说"什么

解析完 URL,浏览器知道了要去哪、取什么,接下来它得把这个需求"说出口",这就是生成 HTTP 请求报文的过程。

HTTP 请求报文的结构非常规整:

GET /dir/page.html HTTP/1.1        ← 请求行(方法 + 路径 + 版本)

Host: www.example.com              ← 消息头(Header)

User-Agent: Mozilla/5.0 ...

Accept-Language: zh-CN,zh;q=0.9

(空行)                            ← 头部结束标志

(消息体,GET 请求通常为空)

  • 方法:最常见的是 GET(我要拿数据)和 POST(我要提交数据)。

  • URI:服务器上资源的路径。

  • 消息头:附带很多"背景信息",告诉服务器浏览器类型、语言偏好、缓存设置等等。

服务器收到后会返回响应报文,格式类似:

HTTP/1.1 200 OK                    ← 状态行

Content-Type: text/html; charset=UTF-8

(空行)

...                   ← 响应体(页面内容)

状态码是个很有意思的设计:200 OK 是成功,301/302 是重定向,404 Not Found 是找不到,500 Internal Server Error 是服务器炸了……这套数字语言开发者都太熟悉了。

有意思的地方:HTTP 的"无状态"设计意味着每次请求都是独立的,服务器不记得你上次来过。这也是为什么我们需要 Cookie/Session 这类机制——本质上是在 HTTP 头里塞一个"认证贴纸",让服务器认出你。


三、DNS 查询:域名到 IP 的翻译官

有了 HTTP 请求,浏览器还差一步——它知道要去 *www.example.com*,但网络世界里真正能用来寻址的是 IP 地址(比如 93.184.216.34),不认识"www.example.com"这种对人友好的名字。

这就需要 DNS(Domain Name System) 出场了。

浏览器会调用操作系统的解析器(Resolver) ,向 DNS 服务器发出查询请求,过程大概是这样的:

浏览器

  ↓ 调用 Socket 库的解析器

本地 DNS 服务器(运营商或公司内网提供)

  ↓ 如果本地没有缓存

根域名服务器(Root DNS)

  ↓ 返回负责 .com 的服务器地址

顶级域名服务器(.com DNS)

  ↓ 返回负责 example.com 的服务器地址

权威域名服务器

  ↓ 返回 www.example.com 的 IP 地址

书里对这个"分级查询"的设计解释得很透彻:为什么不把全球所有域名都存在一台服务器上?因为那台服务器撑不住,而且全球只有一台 DNS 的话,宕机了整个互联网就瞎了。分级的设计让每层服务器只管自己那一块,既高效又可靠。

关于 IP 地址:书里提到 IP 地址其实分两部分——网络号(你在哪个网段)和主机号(这个网段里的第几台机器)。这就好比一个地址"北京市朝阳区XX小区101号"——北京市朝阳区 XX 小区是网络号,101 号是主机号,路由器靠这个找到目的地所在的网络,再交给那个网络里的具体机器。


四、Socket:建立连接的那根"管道"

IP 地址到手,HTTP 报文准备好,终于到了真正发送数据的环节。

这里要出场的主角是 Socket(套接字)

Socket 是操作系统提供给应用程序的网络通信接口,你可以把它想象成一个插孔——浏览器这边有一个,服务器那边有一个,中间拉一根管道,数据就可以互相流通了。

建立 Socket 连接的流程:

  1. socket()     → 创建一个套接字(得到一个"描述符")

  2. connect()    → 拿着 IP + 端口,向服务器发起连接请求

  3. write()      → 把 HTTP 请求数据塞进管道

  4. read()       → 从管道里读取服务器返回的响应

  5. close()      → 通信完毕,关闭连接

端口号是这里的关键概念之一。服务器同时跑着很多服务(Web、FTP、邮件……),端口号就是"部门门牌",HTTP 默认是 80 端口,HTTPS 是 443 端口。浏览器发起连接时,目标 IP + 目标端口缺一不可。

一个小细节:HTTP/1.0 时代,每次请求完服务器就会主动关闭连接,下次再请求要重新三次握手;HTTP/1.1 引入了长连接(Keep-Alive) ,一次 TCP 连接可以发多个 HTTP 请求,省去了大量重复建连的开销——这对于一个动辄需要加载几十个资源文件的网页来说,性能提升相当可观。


五、把整条链路串起来看

读完第一章,整个流程在脑子里终于清晰地串起来了:

你在浏览器输入 www.example.com/index.html

           ↓

浏览器解析 URL(协议=https, 服务器=www.example.com, 路径=/index.html)

           ↓

生成 HTTP 请求报文(GET /index.html HTTP/1.1)

           ↓

DNS 查询:www.example.com → 93.184.216.34

           ↓

调用 Socket 库,向 93.184.216.34:443 发起 TCP 连接

           ↓

通过 write() 发送 HTTP 请求

           ↓

通过 read() 接收 HTTP 响应

           ↓

浏览器渲染页面

每一步都有明确的职责,每一层都做好自己分内的事——这正是分层设计的精妙之处。


六、对我的触动:从"会用"到"懂了"

这本书给我最大的冲击,不是某个具体的知识点,而是视角的转换

以前看待 HTTP 请求,我的视角是"我调用了一个 fetch,然后数据回来了"。读完这一章,我的视角变成了"我的一份数据,经历了 URL 解析、HTTP 封装、DNS 查询、Socket 建立,最终才以电信号的形式离开我的网卡"。

这种感觉很像是——原来你只知道插上电插座灯就亮了,现在你终于知道发电站、输电线、变压器是怎么协作的。

对开发者的一点实际意义

  • 当线上接口偶发超时,你会想到"是不是 DNS 解析变慢了?是不是连接没有复用导致频繁三次握手?"

  • 当排查跨域问题,你知道那不是什么玄学,就是 HTTP 请求头和响应头之间的一次"协商"。

  • 当优化首屏加载速度,你会想到 DNS 预解析、HTTP/2 多路复用、连接预热这些真实有效的手段。

底层原理,是性能优化和问题排查的底气。


结语

《网络是怎样连接的》第一章只是一个开始。后续的章节还会深入到协议栈的内部、网卡的工作方式、路由器的转发逻辑……这趟数据包的旅程还很长。

但第一章已经给了我足够的惊喜——它把我从"知道有 DNS 这个东西"带到了"理解 DNS 为什么这么设计、它的分级查询解决了什么问题"。这就是好书的价值:不只给答案,还给你思考框架


强烈推荐给每一个想把计算机网络从八股文变成真理解的开发者。


如果这篇文章对你有帮助,欢迎点赞收藏~后续我会持续更新这本书的读书笔记 **🚀