从网址到页面 · 计算机网络
输入网址按下回车之后,发生了什么?
课程目录为什么需要它
这是经典面试题,因为答案涉及这门课的所有内容:URL、DNS、TCP、TLS、HTTP、缓存和浏览器。能按顺序讲清楚这个过程,并说出每种故障会出在哪一步,说明你真正理解了 Web 是怎么拼起来的。
直觉理解
以 https://shop.example.com/cart?id=7 为例:
- 解析 URL:协议
https、主机shop.example.com、端口 443(https 的默认端口)、路径/cart、查询id=7。 - DNS:查主机的地址(浏览器缓存、操作系统缓存,然后是解析器)。
- TCP:和 地址:443 三次握手。
- TLS:协商加密密钥,并检查服务器的证书对这个名字是否有效。
- HTTP:发送
GET /cart?id=7和头部(包括 cookie);收到状态码、头部和 HTML。 - 渲染:浏览器解析 HTML,再去取 CSS、JavaScript 和图片(更多请求,通常复用连接),然后画出页面。
缓存可以跳过某些步骤:缓存的 DNS 答案跳过第 2 步,缓存的文件跳过第 3–5 步。
定义
网址 URL
scheme://host:port/path?query#fragment. The fragment (#…) never leaves the browser.协议://主机:端口/路径?查询#片段。片段(#……)永远不会离开浏览器。
TLS 证书
A file signed by a trusted authority saying "this public key belongs to shop.example.com". Browsers refuse the connection if it is expired or for another name.由受信任机构签名的文件,声明「这个公钥属于 shop.example.com」。证书过期或名字不符时,浏览器会拒绝连接。
示例
把 URL 拆开
动手试试urllib.parse 把 URL 拆成每一步需要的部分。
from urllib.parse import urlsplit
u = urlsplit("https://shop.example.com/cart?id=7#reviews")
port = u.port or {"https": 443, "http": 80}[u.scheme]
print(u.scheme, u.hostname, port)
print(u.path, u.query, u.fragment)逐步执行
- L4没写端口,就用协议的默认端口。
- L5这是 DNS 和 TCP 需要的信息。
https shop.example.com 443 - L6片段只留在浏览器里。
/cart id=7 reviews
把整个过程列出来
动手试试一个函数,为任意 URL 描述整个过程;DNS 答案已缓存时跳过 DNS。
from urllib.parse import urlsplit
def journey(url, dns_cache):
u = urlsplit(url)
port = u.port or {"https": 443, "http": 80}[u.scheme]
steps = []
if u.hostname not in dns_cache:
steps.append("DNS " + u.hostname)
steps.append(f"TCP :{port}")
if u.scheme == "https":
steps.append("TLS")
steps.append("GET " + (u.path or "/"))
return steps
print(journey("https://shop.example.com/cart", set()))
print(journey("http://shop.example.com", {"shop.example.com"}))逐步执行
- L7有缓存答案就跳过查询。
- L10只有 HTTPS 才加 TLS。
- L15DNS 有缓存,端口 80 的普通 HTTP,路径默认是 /。
['TCP :80', 'GET /']
常见错误
私密内容用 http://
没有 TLS,路径上的任何人(咖啡店 Wi-Fi、路由器)都能读取和篡改流量,包括 cookie 和密码。
忘了后面还有很多请求
加载一个页面往往要几十个请求(CSS、脚本、图片、API)。页面慢通常慢在这些地方,而不是第一个 HTML。
小测验
1. 浏览器提示证书属于另一个名字。哪一步失败了?
查看答案
答案:A
检查证书是 TLS 握手的一部分,发生在发送任何 HTTP 之前。
2. 这段代码会输出什么?
from urllib.parse import urlsplit
u = urlsplit("http://localhost:8000/api/items?sort=price")
print(u.hostname, u.port, u.path)查看答案
答案:A
端口明确写出来了;查询和路径是分开的。
动手练习
3 道练习,分三层:先预测程序的输出,再按新需求改程序,最后从零写一个。代码在浏览器里运行,提交马上判题。
- 预测输出默认端口
准确写出这段程序的输出。
- 改需求别忘了 TLS
steps(url)列出访问某个 URL 的网络步骤,但它从不包含 TLS,而且端口总是 80。修好它:HTTPS 用 443 端口,并在 TCP 之后加上"TLS"。URL 里写明的端口优先于默认端口。 - 从零写坏在哪一步?
写函数
diagnose(error),把错误信息对应到失败的那一步:- 包含
Could not resolve→"DNS" - 包含
Connection refused或timed out→"TCP" - 包含
certificate→"TLS" - 以
HTTP/开头 → 状态码的类别:"HTTP 4xx"或"HTTP 5xx"(比如HTTP/1.1 503 Service Unavailable) - 其他 →
"unknown"
- 包含
本课术语
| 术语 | 中文 | 英文定义 |
|---|---|---|
| URL | 网址 | scheme://host:port/path?query#fragment. |
| TLS | 传输层安全 | Encryption and server identity checks for a connection; the S in HTTPS. |
| Certificate | 证书 | A signed statement that a public key belongs to a domain name. |