人人都能学编程
English 开始学习
核心 · 计算机网络第 6 课 / 共 6 课免费阅读

从网址到页面 · 计算机网络

输入网址按下回车之后,发生了什么?

课程目录

为什么需要它

这是经典面试题,因为答案涉及这门课的所有内容:URL、DNS、TCP、TLS、HTTP、缓存和浏览器。能按顺序讲清楚这个过程,并说出每种故障会出在哪一步,说明你真正理解了 Web 是怎么拼起来的。

直觉理解

以 https://shop.example.com/cart?id=7 为例:

  1. 解析 URL:协议 https、主机 shop.example.com、端口 443(https 的默认端口)、路径 /cart、查询 id=7。
  2. DNS:查主机的地址(浏览器缓存、操作系统缓存,然后是解析器)。
  3. TCP:和 地址:443 三次握手。
  4. TLS:协商加密密钥,并检查服务器的证书对这个名字是否有效。
  5. HTTP:发送 GET /cart?id=7 和头部(包括 cookie);收到状态码、头部和 HTML。
  6. 渲染:浏览器解析 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)
逐步执行
  1. L4没写端口,就用协议的默认端口。
  2. L5这是 DNS 和 TCP 需要的信息。https shop.example.com 443
  3. 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"}))
逐步执行
  1. L7有缓存答案就跳过查询。
  2. L10只有 HTTPS 才加 TLS。
  3. L15DNS 有缓存,端口 80 的普通 HTTP,路径默认是 /。['TCP :80', 'GET /']

常见错误

私密内容用 http://

没有 TLS,路径上的任何人(咖啡店 Wi-Fi、路由器)都能读取和篡改流量,包括 cookie 和密码。

忘了后面还有很多请求

加载一个页面往往要几十个请求(CSS、脚本、图片、API)。页面慢通常慢在这些地方,而不是第一个 HTML。

小测验

1. 浏览器提示证书属于另一个名字。哪一步失败了?

  1. ATLS
  2. BDNS
  3. C渲染
查看答案

答案: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)
  1. A
    localhost 8000 /api/items
  2. B
    localhost 80 /api/items
  3. C
    localhost:8000 None /api/items?sort=price
查看答案

答案:A

端口明确写出来了;查询和路径是分开的。

动手练习

3 道练习,分三层:先预测程序的输出,再按新需求改程序,最后从零写一个。代码在浏览器里运行,提交马上判题。

  1. 预测输出默认端口

    准确写出这段程序的输出。

  2. 改需求别忘了 TLS

    steps(url) 列出访问某个 URL 的网络步骤,但它从不包含 TLS,而且端口总是 80。修好它:HTTPS 用 443 端口,并在 TCP 之后加上 "TLS"。URL 里写明的端口优先于默认端口。

  3. 从零写坏在哪一步?

    写函数 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.