docs: 重构 README 附录展示 & 新增多个附录交互组件
README 更新: - 移除顶部 header.png 横幅图片 - 新增「附录知识库」板块,以 3×3 网格展示 9 大知识领域精选内容 - 附录链接指向部署版网站 (datawhalechina.github.io) - 阶段表格新增「附录」行,突出 80+ 交互式专题 - 章节标题「新手入门 & PM」简化为「零基础入门」 - News 新增 2026-02-25 附录知识库更新条目 新增交互组件: - 异步任务队列 (async-task-queues) 演示组件 - 文件存储 (file-storage) 演示组件 - 项目架构 (project-architecture) 演示组件 - 限流与背压 (rate-limiting) 演示组件 - 搜索引擎 (search-engines) 演示组件 - 计算机基础: AppLaunch/BiosUefi/OSBoot 等启动流程演示组件 新增附录文档: - 前端项目架构 (frontend-project-architecture.md) - 后端项目架构 (backend-project-architecture.md) 内容优化: - 算法思维、数据结构、编程语言、调试艺术等多篇附录内容更新 - HTML/CSS 布局、请求旅程等前后端文档完善 - 附录索引页 (index.md) 同步更新
This commit is contained in:
@@ -1,3 +1,295 @@
|
||||
# 一个请求的完整旅程
|
||||
|
||||
> 待实现
|
||||
::: tip 前言
|
||||
**当你在浏览器里输入一个网址按下回车,到页面显示出来,中间到底发生了什么?** 这个问题是面试经典题,更是理解整个 Web 架构的钥匙。搞懂这条链路,你就能理解前端、后端、网络、数据库是怎么协作的。
|
||||
:::
|
||||
|
||||
**这篇文章会带你学什么?**
|
||||
|
||||
学完这章后,你将获得:
|
||||
|
||||
- **全链路视角**:理解一个 HTTP 请求从发出到返回的完整过程
|
||||
- **各层职责认知**:DNS、TCP、负载均衡、Web 服务器、应用服务器、数据库各自做什么
|
||||
- **问题定位能力**:请求慢或失败时,知道从哪一层开始排查
|
||||
- **性能优化思路**:每一层都有优化空间,知道优化点在哪里
|
||||
|
||||
| 章节 | 内容 | 核心概念 |
|
||||
|-----|------|---------|
|
||||
| **第 1 章** | 浏览器发起请求 | DNS 解析、TCP 连接、HTTP 请求 |
|
||||
| **第 2 章** | 网络传输 | 路由、CDN、负载均衡 |
|
||||
| **第 3 章** | 服务器处理 | Web 服务器、应用逻辑、数据库查询 |
|
||||
| **第 4 章** | 响应返回 | 序列化、压缩、渲染 |
|
||||
| **第 5 章** | 全链路优化 | 缓存、连接复用、异步处理 |
|
||||
|
||||
---
|
||||
|
||||
## 0. 全景图:一个请求经历了什么?
|
||||
|
||||
用一个比喻来理解:你在网上下单买书,这个过程和 HTTP 请求惊人地相似。
|
||||
|
||||
| 请求阶段 | 买书类比 | 技术对应 |
|
||||
|---------|---------|---------|
|
||||
| 输入网址 | 你说"我要去某某书店" | 浏览器解析 URL |
|
||||
| DNS 解析 | 查地图找到书店地址 | 域名 → IP 地址 |
|
||||
| TCP 连接 | 走到书店门口,推门进去 | 三次握手建立连接 |
|
||||
| 发送请求 | 告诉店员"我要《xxx》这本书" | HTTP 请求报文 |
|
||||
| 服务器处理 | 店员去仓库找书、查库存、算价格 | 应用逻辑 + 数据库查询 |
|
||||
| 返回响应 | 店员把书递给你 | HTTP 响应报文 |
|
||||
| 浏览器渲染 | 你打开书开始阅读 | HTML/CSS/JS 解析渲染 |
|
||||
|
||||
<RequestJourneyFlow />
|
||||
|
||||
---
|
||||
|
||||
## 1. 浏览器发起请求
|
||||
|
||||
### 1.1 URL 解析
|
||||
|
||||
当你输入 `https://api.example.com/books?id=123` 时,浏览器会把它拆解成几个部分:
|
||||
|
||||
| 部分 | 值 | 含义 |
|
||||
|-----|-----|------|
|
||||
| 协议 | `https` | 用加密方式通信 |
|
||||
| 域名 | `api.example.com` | 服务器的"名字" |
|
||||
| 路径 | `/books` | 要访问的资源 |
|
||||
| 查询参数 | `id=123` | 附加条件 |
|
||||
|
||||
### 1.2 DNS 解析:域名 → IP 地址
|
||||
|
||||
计算机不认识域名,只认识 IP 地址(如 `93.184.216.34`)。DNS 就是互联网的"电话簿"。
|
||||
|
||||
```
|
||||
浏览器缓存 → 系统缓存 → 路由器缓存 → ISP DNS → 根域名服务器
|
||||
↓ 命中就直接用,不命中就往下查
|
||||
```
|
||||
|
||||
::: tip DNS 缓存的意义
|
||||
如果每次请求都从根域名服务器查起,全球互联网会被 DNS 查询压垮。所以每一层都有缓存,大部分请求在浏览器或系统层就能解析完成。
|
||||
:::
|
||||
|
||||
### 1.3 TCP 三次握手
|
||||
|
||||
找到 IP 地址后,浏览器需要和服务器"建立连接"。TCP 用三次握手确保双方都准备好了:
|
||||
|
||||
```
|
||||
客户端 → 服务器:你好,我想连接(SYN)
|
||||
服务器 → 客户端:好的,我准备好了(SYN + ACK)
|
||||
客户端 → 服务器:收到,开始通信(ACK)
|
||||
```
|
||||
|
||||
如果是 HTTPS,还需要额外的 TLS 握手来协商加密方式。
|
||||
|
||||
### 1.4 发送 HTTP 请求
|
||||
|
||||
连接建立后,浏览器发送 HTTP 请求报文:
|
||||
|
||||
```http
|
||||
GET /books?id=123 HTTP/1.1
|
||||
Host: api.example.com
|
||||
Accept: application/json
|
||||
Authorization: Bearer eyJhbGci...
|
||||
User-Agent: Chrome/120.0
|
||||
```
|
||||
|
||||
| 组成部分 | 内容 |
|
||||
|---------|------|
|
||||
| 请求行 | 方法(GET)+ 路径 + 协议版本 |
|
||||
| 请求头 | 元信息:身份认证、期望的数据格式等 |
|
||||
| 请求体 | POST/PUT 请求才有,携带要提交的数据 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 网络传输:请求在路上
|
||||
|
||||
### 2.1 路由转发
|
||||
|
||||
请求离开你的电脑后,会经过多个路由器的转发,就像快递经过多个中转站:
|
||||
|
||||
```
|
||||
你的电脑 → 家庭路由器 → 运营商网络 → 骨干网 → 目标机房
|
||||
```
|
||||
|
||||
每个路由器根据 IP 地址决定"下一跳"往哪里转发。可以用 `traceroute` 命令查看请求经过了哪些节点。
|
||||
|
||||
### 2.2 CDN 加速
|
||||
|
||||
如果目标网站使用了 CDN(内容分发网络),请求可能不需要到达源服务器:
|
||||
|
||||
| 场景 | 走向 |
|
||||
|-----|------|
|
||||
| 请求静态资源(图片、CSS、JS) | CDN 边缘节点直接返回 |
|
||||
| 请求动态数据(API) | 穿透 CDN,到达源服务器 |
|
||||
|
||||
CDN 的本质是"把内容提前放到离用户最近的地方"。
|
||||
|
||||
### 2.3 负载均衡
|
||||
|
||||
大型网站不会只有一台服务器。负载均衡器负责把请求分配到多台服务器上:
|
||||
|
||||
```
|
||||
用户请求 → 负载均衡器 → 服务器 A(30% 流量)
|
||||
→ 服务器 B(30% 流量)
|
||||
→ 服务器 C(40% 流量)
|
||||
```
|
||||
|
||||
常见的分配策略:
|
||||
|
||||
| 策略 | 原理 | 适用场景 |
|
||||
|-----|------|---------|
|
||||
| 轮询 | 依次分配 | 服务器配置相同 |
|
||||
| 加权轮询 | 按权重分配 | 服务器配置不同 |
|
||||
| IP 哈希 | 同一用户固定到同一台 | 需要会话保持 |
|
||||
| 最少连接 | 分给当前连接最少的 | 请求处理时间差异大 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 服务器处理:厨房里发生了什么
|
||||
|
||||
请求到达服务器后,会经过多层处理。
|
||||
|
||||
### 3.1 Web 服务器(Nginx / Apache)
|
||||
|
||||
第一个接收请求的通常是 Web 服务器,它负责:
|
||||
|
||||
| 职责 | 说明 |
|
||||
|-----|------|
|
||||
| 静态文件服务 | 直接返回 HTML、CSS、JS、图片 |
|
||||
| 反向代理 | 把 API 请求转发给后端应用 |
|
||||
| SSL 终止 | 处理 HTTPS 加密解密 |
|
||||
| 请求过滤 | 拦截恶意请求、限流 |
|
||||
|
||||
### 3.2 应用服务器处理
|
||||
|
||||
Web 服务器把请求转发给应用服务器(Node.js、Spring、Django 等),处理流程:
|
||||
|
||||
```
|
||||
请求进入 → 中间件链 → 路由匹配 → 控制器 → 服务层 → 数据访问层
|
||||
```
|
||||
|
||||
**中间件**做的事情:
|
||||
|
||||
1. 解析请求体(JSON、表单数据)
|
||||
2. 验证身份(检查 Token)
|
||||
3. 检查权限(这个用户能访问这个接口吗?)
|
||||
4. 记录日志(谁在什么时候访问了什么)
|
||||
|
||||
### 3.3 数据库查询
|
||||
|
||||
大部分请求最终都要和数据库打交道:
|
||||
|
||||
```
|
||||
应用代码:SELECT * FROM books WHERE id = 123
|
||||
↓
|
||||
数据库引擎:解析 SQL → 查询优化 → 执行计划 → 读取数据
|
||||
↓
|
||||
返回结果:{ id: 123, title: "xxx", price: 59.9 }
|
||||
```
|
||||
|
||||
::: tip 数据库是最常见的性能瓶颈
|
||||
网络传输通常是毫秒级,应用逻辑也很快,但一个没有索引的数据库查询可能要几秒甚至几十秒。所以"慢请求"大概率是数据库查询慢。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 4. 响应返回:数据的归途
|
||||
|
||||
### 4.1 构造 HTTP 响应
|
||||
|
||||
服务器处理完后,构造响应报文:
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Content-Encoding: gzip
|
||||
Cache-Control: max-age=3600
|
||||
|
||||
```
|
||||
|
||||
| 组成部分 | 内容 |
|
||||
|---------|------|
|
||||
| 状态行 | 协议版本 + 状态码(200 成功、404 未找到、500 服务器错误) |
|
||||
| 响应头 | 数据格式、缓存策略、压缩方式等 |
|
||||
| 响应体 | 实际的数据内容(JSON、HTML 等) |
|
||||
|
||||
### 4.2 数据压缩
|
||||
|
||||
服务器通常会用 gzip 或 brotli 压缩响应体,减少传输量:
|
||||
|
||||
| 压缩算法 | 压缩率 | 速度 |
|
||||
|---------|--------|------|
|
||||
| gzip | 约 70% | 快 |
|
||||
| brotli | 约 80% | 较慢但压缩更好 |
|
||||
|
||||
一个 100KB 的 JSON,压缩后可能只有 20-30KB。
|
||||
|
||||
### 4.3 浏览器渲染
|
||||
|
||||
浏览器收到响应后:
|
||||
|
||||
1. **解析 HTML** → 构建 DOM 树
|
||||
2. **解析 CSS** → 构建样式树
|
||||
3. **合并** → 生成渲染树
|
||||
4. **布局** → 计算每个元素的位置和大小
|
||||
5. **绘制** → 把像素画到屏幕上
|
||||
|
||||
<RequestTimeline />
|
||||
|
||||
---
|
||||
|
||||
## 5. 全链路优化:每一层都能更快
|
||||
|
||||
### 5.1 各层优化手段
|
||||
|
||||
| 层级 | 优化手段 | 效果 |
|
||||
|-----|---------|------|
|
||||
| DNS | DNS 预解析、使用快速 DNS 服务 | 减少 DNS 查询时间 |
|
||||
| 网络 | CDN、HTTP/2、连接复用 | 减少传输延迟 |
|
||||
| 服务器 | 缓存(Redis)、异步处理 | 减少处理时间 |
|
||||
| 数据库 | 索引、查询优化、读写分离 | 减少查询时间 |
|
||||
| 前端 | 懒加载、代码分割、资源压缩 | 减少渲染时间 |
|
||||
|
||||
### 5.2 缓存:最有效的优化
|
||||
|
||||
缓存存在于请求链路的每一层:
|
||||
|
||||
```
|
||||
浏览器缓存 → CDN 缓存 → 反向代理缓存 → 应用缓存(Redis)→ 数据库缓存
|
||||
```
|
||||
|
||||
::: tip 缓存的本质
|
||||
用空间换时间。把计算过的结果存起来,下次直接用,不用重新算。缓存命中率每提高 10%,系统性能可能提升数倍。
|
||||
:::
|
||||
|
||||
### 5.3 请求失败时的排查思路
|
||||
|
||||
| 现象 | 可能的问题层 | 排查方法 |
|
||||
|-----|------------|---------|
|
||||
| 完全无响应 | DNS / 网络 | ping、nslookup |
|
||||
| 连接超时 | 网络 / 服务器宕机 | telnet、curl |
|
||||
| 返回 4xx | 客户端请求有误 | 检查 URL、参数、Token |
|
||||
| 返回 5xx | 服务器内部错误 | 查看服务器日志 |
|
||||
| 响应很慢 | 数据库 / 应用逻辑 | 查看慢查询日志、APM 工具 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 总结
|
||||
|
||||
一个 HTTP 请求的完整旅程:
|
||||
|
||||
1. **浏览器**:解析 URL → DNS 查询 → TCP 连接 → 发送请求
|
||||
2. **网络**:路由转发 → CDN 判断 → 负载均衡分发
|
||||
3. **服务器**:Web 服务器接收 → 中间件处理 → 业务逻辑 → 数据库查询
|
||||
4. **返回**:构造响应 → 压缩 → 网络传输 → 浏览器渲染
|
||||
|
||||
::: tip 理解全链路的价值
|
||||
当你能在脑中画出请求的完整链路时,遇到任何问题都能快速定位到是哪一层出了问题。这是从"初级开发"到"能独立排查问题"的关键跨越。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 延伸阅读
|
||||
|
||||
- [HTTP 权威指南](https://developer.mozilla.org/zh-CN/docs/Web/HTTP) — MDN 的 HTTP 文档
|
||||
- [High Performance Browser Networking](https://hpbn.co/) — 浏览器网络性能优化
|
||||
- [What happens when...](https://github.com/alex/what-happens-when) — 经典的"输入 URL 后发生了什么"详解
|
||||
- [What happens when...](https://github.com/alex/what-happens-when) — 经典的"输入 URL 后发生了什么"详解
|
||||
|
||||
Reference in New Issue
Block a user