1229 lines
37 KiB
Markdown
1229 lines
37 KiB
Markdown
|
|
---
|
|||
|
|
tags: [MySQL, Docker, Gin, JWT, Protobuf, Nginx, CORS, Exam Review]
|
|||
|
|
create time: 2026-05-14 10:30
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 金山考试 - 武汉科技大学第5次考试复习笔记_26/04/16
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
本文档是 **武汉科技大学第5次考试** 的完整题目回顾与知识点解析。本次考试涵盖 8 大技术领域:**Docker、MySQL、Gin 框架、Go 并发编程、JWT & Session、Protobuf、Nginx & CDN、CORS**。以下内容将原始 40 道单选题和多选题按知识模块重新组织,每道题保留原题和答案,并补充教学讲解、代码示例和图表。
|
|||
|
|
|
|||
|
|
> [!NOTE] 使用建议
|
|||
|
|
> - 先快速浏览所有错题标记(作答答案 ≠ 正确答案),确定薄弱模块
|
|||
|
|
> - 重点阅读每个模块的 **核心概念图** 和 **易错点提示**
|
|||
|
|
> - 代码块均经过精简注释,核心逻辑一目了然
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、Docker 基础命令
|
|||
|
|
|
|||
|
|
### 核心概念图
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph LR
|
|||
|
|
A[Dockerfile] -->|docker build| B[镜像 Image]
|
|||
|
|
B -->|docker run| C[容器 Container]
|
|||
|
|
C -->|docker stop| D[已停止]
|
|||
|
|
C -->|docker pause| E[已暂停]
|
|||
|
|
B -->|docker push| F[仓库 Registry]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!TIP] Docker 核心工作流
|
|||
|
|
> **Dockerfile → 构建镜像 → 运行容器 → 推送仓库**,这是最完整的开发到生产流程。
|
|||
|
|
|
|||
|
|
### 原题回顾
|
|||
|
|
|
|||
|
|
#### 第1题:停止容器
|
|||
|
|
|
|||
|
|
> [!EXAMPLE] 易错提醒
|
|||
|
|
> `docker pause` 是"暂停"而非"停止"——它通过 cgroup 将容器进程挂起,内存中数据仍在;`docker stop` 则是发送 SIGTERM 信号后优雅终止。
|
|||
|
|
|
|||
|
|
1.
|
|||
|
|
|
|||
|
|
【单选题】以下哪个命令用于在Docker中停止一个正在运行的容器?(5分)
|
|||
|
|
|
|||
|
|
A. `docker stop`
|
|||
|
|
|
|||
|
|
B. `docker pause`
|
|||
|
|
|
|||
|
|
C. `docker end`
|
|||
|
|
|
|||
|
|
D. `docker halt`
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第2题:构建镜像
|
|||
|
|
|
|||
|
|
> [!EXAMPLE] 关键字记忆
|
|||
|
|
> `build` 对应构建镜像,类似 `"builder"` → `"built image"`。记住 `Dockerfile` + `docker build` 的组合。
|
|||
|
|
|
|||
|
|
2.
|
|||
|
|
|
|||
|
|
【单选题】哪个命令是用于在Docker中构建镜像的?(5分)
|
|||
|
|
|
|||
|
|
A. `docker compose`
|
|||
|
|
|
|||
|
|
B. `docker build`
|
|||
|
|
|
|||
|
|
C. `docker make`
|
|||
|
|
|
|||
|
|
D. `docker assemble`
|
|||
|
|
|
|||
|
|
**正确答案:** B
|
|||
|
|
**作答答案:** B ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第3题:容器与镜像的关系
|
|||
|
|
|
|||
|
|
> [!INFO] 类比理解
|
|||
|
|
> **镜像 = 类(Class)**,**容器 = 实例(Instance)**。就像你可以从同一个类创建多个对象实例一样,你也可以从同一个镜像启动多个容器。
|
|||
|
|
|
|||
|
|
3.
|
|||
|
|
|
|||
|
|
【单选题】关于Docker容器和镜像的关系正确的是?(5分)
|
|||
|
|
|
|||
|
|
A. 容器是镜像的一个实例
|
|||
|
|
|
|||
|
|
B. 镜像可以包含多个容器
|
|||
|
|
|
|||
|
|
C. 容器和镜像是两个没有联系的独立组件
|
|||
|
|
|
|||
|
|
D. 容器比镜像更早出现于Docker技术中
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第4题:查看运行容器
|
|||
|
|
|
|||
|
|
4.
|
|||
|
|
|
|||
|
|
【单选题】在Docker中,通过哪条命令可以查看所有当前运行的容器?(5分)
|
|||
|
|
|
|||
|
|
A. `docker ps`
|
|||
|
|
|
|||
|
|
B. `docker view`
|
|||
|
|
|
|||
|
|
C. `docker list`
|
|||
|
|
|
|||
|
|
D. `docker show`
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
> [!NOTE] docker ps vs docker ps -a
|
|||
|
|
> - `docker ps`:仅显示正在运行的容器
|
|||
|
|
> - `docker ps -a`:显示所有容器(包括已停止的)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第5题:创建并启动容器
|
|||
|
|
|
|||
|
|
5.
|
|||
|
|
|
|||
|
|
【单选题】Docker 中创建并启动一个容器的正确命令是什么?(5分)
|
|||
|
|
|
|||
|
|
A. `docker build -t myimage .`
|
|||
|
|
|
|||
|
|
B. `docker create --name mycontainer myimage`
|
|||
|
|
|
|||
|
|
C. `docker run --name mycontainer myimage`
|
|||
|
|
|
|||
|
|
D. `docker start mycontainer`
|
|||
|
|
|
|||
|
|
**正确答案:** C
|
|||
|
|
**作答答案:** C ✅
|
|||
|
|
|
|||
|
|
> [!WARNING] create vs run
|
|||
|
|
> `docker create` 仅创建容器但不启动;`docker run` 等价于 `create + start` 的组合。考试常考这个细微差别。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第1题(多选):Docker 与虚拟机对比
|
|||
|
|
|
|||
|
|
> [!INFO] Docker vs 虚拟机核心对比
|
|||
|
|
> | 维度 | Docker 容器 | 虚拟机 (VM) |
|
|||
|
|
> |------|-------------|-------------|
|
|||
|
|
> | 启动速度 | 秒级 | 分钟级 |
|
|||
|
|
> | 资源占用 | 共享宿主内核,轻量 | 独立 Guest OS,臃肿 |
|
|||
|
|
> | 隔离性 | 进程级隔离 | 硬件级完全隔离 |
|
|||
|
|
> | 镜像大小 | MB 级别 | GB 级别 |
|
|||
|
|
> | 性能损耗 | 几乎无 | 虚拟化层开销 |
|
|||
|
|
|
|||
|
|
1.
|
|||
|
|
|
|||
|
|
【多选题】Docker与虚拟机的优劣势对比中,下列哪些是正确的?(5分)
|
|||
|
|
|
|||
|
|
A. Docker容器启动比虚拟机更迅速
|
|||
|
|
|
|||
|
|
B. 虚拟机提供了更高的隔离性和安全性
|
|||
|
|
|
|||
|
|
C. Docker比虚拟机需要更多的硬件资源
|
|||
|
|
|
|||
|
|
D. Docker比虚拟机具有更快的性能提升潜力
|
|||
|
|
|
|||
|
|
**正确答案:** ABD
|
|||
|
|
**作答答案:** ABD ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、MySQL 索引与查询优化
|
|||
|
|
|
|||
|
|
### 覆盖索引流程图
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TD
|
|||
|
|
Q[SQL 查询] --> C{SELECT 字段是否都在索引中?}
|
|||
|
|
C -->|是| Cover[✅ 覆盖索引 — 只需扫描索引树]
|
|||
|
|
C -->|否| NoCover[❌ 需要回表 — 先查索引再查主表]
|
|||
|
|
Cover --> Fast[🚀 性能高 — 减少 IO]
|
|||
|
|
NoCover --> Slow[⏱️ 性能低 — 额外 IO 操作]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 函数导致索引失效
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart LR
|
|||
|
|
A["WHERE YEAR(create_time) = 2023"] -->|对字段做运算| B["💥 索引失效 — 全表扫描"]
|
|||
|
|
C["WHERE create_time >= '2023-01-01'"] -->|范围比较,字段无修改| D["✅ 索引命中 — 范围扫描"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!CRITICAL] ⚠️ 索引失效的核心规则
|
|||
|
|
> **对索引字段做任何运算(函数、表达式)都会导致索引失效**。因为索引存储的是原始值,无法匹配计算后的结果。
|
|||
|
|
|
|||
|
|
### 深分页对比
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart LR
|
|||
|
|
A["LIMIT 100000, 10"] -->|传统写法| B["MySQL: 扫描 100010 行 → 丢弃前 100000 行"]
|
|||
|
|
C["WHERE id > last_id LIMIT 10"] -->|游标翻页| D["MySQL: 直接定位到目标位置 → 只读 10 行"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 原题回顾
|
|||
|
|
|
|||
|
|
#### 第8题:索引失效的场景
|
|||
|
|
|
|||
|
|
> [!CAUTION] 高频考点
|
|||
|
|
> 这类题出现在几乎所有后端面试中。**记住口诀:字段不做函数运算,不等于号慎用,LIKE 不以 % 开头才可走索引。**
|
|||
|
|
|
|||
|
|
8.
|
|||
|
|
|
|||
|
|
【单选题】下列哪个WHERE子句中的条件最有可能导致create_time字段上的索引失效?(5分)
|
|||
|
|
|
|||
|
|
A. `WHERE YEAR(create_time) = 2023`
|
|||
|
|
|
|||
|
|
B. `WHERE create_time >= '2023-01-01' AND create_time < '2023-02-01'`
|
|||
|
|
|
|||
|
|
C. `WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31'`
|
|||
|
|
|
|||
|
|
D. `WHERE create_time = '2023-06-01'`
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** B ❌
|
|||
|
|
|
|||
|
|
> [!THINK] 💡 为什么选 A?
|
|||
|
|
> `YEAR()` 是对 `create_time` 字段的函数运算,MySQL 在匹配时无法直接使用 B+ 树索引来加速查找,必须逐行计算判断。而 B、C、D 都是直接用原始值进行比较,可以正常走索引。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第9题:深分页优化写法
|
|||
|
|
|
|||
|
|
9.
|
|||
|
|
|
|||
|
|
【单选题】在大数据表进行LIMIT深分页时,下列哪种SQL写法具有优化作用?(5分)
|
|||
|
|
|
|||
|
|
A. `SELECT * FROM table WHERE id > (SELECT id FROM table ORDER BY id LIMIT 100000, 1) LIMIT 10`
|
|||
|
|
|
|||
|
|
B. `SELECT * FROM table LIMIT 100000, 10`
|
|||
|
|
|
|||
|
|
C. `SELECT * FROM table WHERE name LIKE '%abc%' LIMIT 10`
|
|||
|
|
|
|||
|
|
D. `SELECT * FROM table ORDER BY RAND() LIMIT 10`
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
> [!NOTE] A 选项的本质
|
|||
|
|
> 先用子查询找到第 100001 行的 id 值,然后用 `WHERE id > xxx LIMIT 10` 直接定位到目标页,避免扫描大量无用数据。注意:这只适用于有序且无删除空洞的场景。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第10题:深分页优化技术
|
|||
|
|
|
|||
|
|
10.
|
|||
|
|
|
|||
|
|
【单选题】在优化MySQL的深分页查询(如 LIMIT 100000, 10)时,推荐使用哪种技术以显著减少扫描的行数?(5分)
|
|||
|
|
|
|||
|
|
A. 基于索引的子查询配合主键筛选
|
|||
|
|
|
|||
|
|
B. 添加更多字段到SELECT查询列表
|
|||
|
|
|
|||
|
|
C. 在ORDER BY后对LIMIT增加OFFSET参数
|
|||
|
|
|
|||
|
|
D. 增加连接数以提升并发执行
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第11题:覆盖索引的实际应用
|
|||
|
|
|
|||
|
|
> [!INFO] 什么是覆盖索引?
|
|||
|
|
> 当 SQL 查询的所有字段都能从索引中直接获取,而不需要再去主表中查数据(即"回表"),就是使用了覆盖索引。
|
|||
|
|
|
|||
|
|
11.
|
|||
|
|
|
|||
|
|
【单选题】如果有如下联合索引KEY(idx_col1_col2) (col1, col2),执行 `SELECT col1 FROM table WHERE col1=5` 时,下列哪项说法正确?(5分)
|
|||
|
|
|
|||
|
|
A. 该查询可以使用覆盖索引,并且只扫描索引
|
|||
|
|
|
|||
|
|
B. 该查询不能使用索引
|
|||
|
|
|
|||
|
|
C. 该查询必须回表查询主表数据
|
|||
|
|
|
|||
|
|
D. 该查询会进行全表扫描
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
> [!THINK] 💡 为什么能用覆盖索引?
|
|||
|
|
> 联合索引 `(col1, col2)` 的 B+ 树叶子节点上存的就是 `(col1, col2)` 的值。既然只需要 `col1`,那直接在索引树上找到即可,无需回表。但如果查询的是 `SELECT col2 WHERE col1=5`,同样也能覆盖索引——因为联合索引包含了两个字段。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第12题:覆盖索引的概念
|
|||
|
|
|
|||
|
|
> [!CAUTION] 错题回顾
|
|||
|
|
> 这道题你做错了,说明对覆盖索引的核心价值还不够清晰——它的本质是 **"只访问索引,不访问表"**。
|
|||
|
|
|
|||
|
|
12.
|
|||
|
|
|
|||
|
|
【单选题】以下关于MySQL覆盖索引的说法,哪项是正确的?(5分)
|
|||
|
|
|
|||
|
|
A. 覆盖索引可以减少IO,因为查询只需访问索引
|
|||
|
|
|
|||
|
|
B. 覆盖索引只能用于InnoDB引擎
|
|||
|
|
|
|||
|
|
C. 覆盖索引不能用于联合索引
|
|||
|
|
|
|||
|
|
D. 覆盖索引使用时必须回表查询原始数据
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** D ❌
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第13题:使用覆盖索引的条件
|
|||
|
|
|
|||
|
|
13.
|
|||
|
|
|
|||
|
|
【单选题】在MySQL中,什么情况下可以使用覆盖索引来优化查询?(5分)
|
|||
|
|
|
|||
|
|
A. 查询的字段全部被所用的索引覆盖,无需回表查询主表数据
|
|||
|
|
|
|||
|
|
B. 查询字段必须是聚合函数的字段
|
|||
|
|
|
|||
|
|
C. 只有当表中没有主键时才能使用覆盖索引
|
|||
|
|
|
|||
|
|
D. 只有当表有唯一索引时才能使用覆盖索引
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、MySQL 慢查询综合优化
|
|||
|
|
|
|||
|
|
### 优化策略金字塔
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
quadrantChart
|
|||
|
|
title "MySQL 慢查询优化策略优先级"
|
|||
|
|
x-axis "低实施难度" --> "高实施难度"
|
|||
|
|
y-axis "高效益" --> "低效益"
|
|||
|
|
"SQL改写": [0.15, 0.9]
|
|||
|
|
"加索引": [0.3, 0.8]
|
|||
|
|
"EXPLAIN分析": [0.1, 0.85]
|
|||
|
|
"缓存层(Redis)": [0.5, 0.7]
|
|||
|
|
"硬件升级": [0.9, 0.3]
|
|||
|
|
"分库分表": [0.95, 0.6]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 原题回顾
|
|||
|
|
|
|||
|
|
#### 第3题(多选):慢查询措施
|
|||
|
|
|
|||
|
|
3.
|
|||
|
|
|
|||
|
|
【多选题】在优化MySQL数据库时,如果遇到慢查询,应该考虑采取哪些措施?(5分)
|
|||
|
|
|
|||
|
|
A. 分析执行计划
|
|||
|
|
|
|||
|
|
B. 调整数据库系统的硬件配置
|
|||
|
|
|
|||
|
|
C. 优化程序的业务逻辑
|
|||
|
|
|
|||
|
|
D. 使用存储过程简化复杂查询
|
|||
|
|
|
|||
|
|
**正确答案:** ABCD
|
|||
|
|
**作答答案:** ACD ❌
|
|||
|
|
|
|||
|
|
> [!THINK] 💡 为什么不排除 B 和 D?
|
|||
|
|
> - **B 是合理的**:如果 SQL 已经无可优化空间,硬件升级(如换 SSD、加内存)确实能改善性能
|
|||
|
|
> - **D 在某些场景有效**:存储过程可以减少网络往返次数,适合批量处理场景
|
|||
|
|
> - 这是一个**多选题**,题目问的是"哪些应该考虑",而非"最佳方案是什么"
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第4题(多选):提高查询性能的措施
|
|||
|
|
|
|||
|
|
4.
|
|||
|
|
|
|||
|
|
【多选题】在进行MySQL性能优化时,可以采取哪些措施来提高查询性能?(5分)
|
|||
|
|
|
|||
|
|
A. 使用索引来加速查询
|
|||
|
|
|
|||
|
|
B. 禁用所有外键以减少约束检查
|
|||
|
|
|
|||
|
|
C. 选择合适的存储引擎
|
|||
|
|
|
|||
|
|
D. 定期进行表碎片整理
|
|||
|
|
|
|||
|
|
**正确答案:** ACD
|
|||
|
|
**作答答案:** ABCD ❌
|
|||
|
|
|
|||
|
|
> [!WARNING] 为什么排除 B?
|
|||
|
|
> `禁用所有外键` 是错误的优化思路。外键保证数据完整性,盲目禁用会导致脏数据。如果性能瓶颈确实在外键检查,应该考虑架构层面的解耦(如用应用层校验替代数据库外键约束),而不是粗暴地"禁用所有"。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第5题(多选):慢查询优化方式
|
|||
|
|
|
|||
|
|
5.
|
|||
|
|
|
|||
|
|
【多选题】在Mysql中,针对慢查询优化有哪些有效方式?(5分)
|
|||
|
|
|
|||
|
|
A. 可以通过为查询字段建立合适的索引以减少全表扫描
|
|||
|
|
|
|||
|
|
B. 查询时尽量避免使用 SELECT *,只查需要的字段有助于提升性能
|
|||
|
|
|
|||
|
|
C. 增加表的数据量可以显著提高查询效率
|
|||
|
|
|
|||
|
|
D. 可以通过分析慢查询日志定位并优化低效的SQL语句
|
|||
|
|
|
|||
|
|
**正确答案:** ABD
|
|||
|
|
**作答答案:** ABD ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第7题(多选):优化查询语句的方法
|
|||
|
|
|
|||
|
|
7.
|
|||
|
|
|
|||
|
|
【多选题】优化MySQL查询语句的方法(5分)
|
|||
|
|
|
|||
|
|
A. 使用正确的索引
|
|||
|
|
|
|||
|
|
B. 避免 SELECT *,只获取必需的列
|
|||
|
|
|
|||
|
|
C. 使用 GORM 可以提升查询性能
|
|||
|
|
|
|||
|
|
D. 使用 EXPLAIN 查看查询计划,然后针对性优化
|
|||
|
|
|
|||
|
|
**正确答案:** ABD
|
|||
|
|
**作答答案:** ABCD ❌
|
|||
|
|
|
|||
|
|
> [!CAUTION] 为什么排除 C?
|
|||
|
|
> GORM 是一个 ORM 框架,它能简化开发但**不会自动提升查询性能**——如果写出的 SQL 本身有问题(比如 N+1 查询),GORM 反而会生成更差的 SQL。性能优化取决于你写的查询语句本身。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第8题(多选):索引优化的考虑因素
|
|||
|
|
|
|||
|
|
8.
|
|||
|
|
|
|||
|
|
【多选题】关于MySQL数据库索引优化的考虑因素有哪些?(5分)
|
|||
|
|
|
|||
|
|
A. 考虑为那些经常作为查询条件的列添加索引
|
|||
|
|
|
|||
|
|
B. 为经常要排序、分组和联合操作的字段建立索引
|
|||
|
|
|
|||
|
|
C. 为经常更新的字段添加索引
|
|||
|
|
|
|||
|
|
D. 避免为表中的每个列都建立索引
|
|||
|
|
|
|||
|
|
**正确答案:** ABD
|
|||
|
|
**作答答案:** ABCD ❌
|
|||
|
|
|
|||
|
|
> [!CAUTION] 为什么排除 C?
|
|||
|
|
> **索引不是免费的!** 每次 INSERT/UPDATE 都需要更新索引树,频繁更新的字段加索引会显著拖慢写入性能。索引的原则是"多读少写的字段优先建索引"。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、MySQL 多选型错题精讲
|
|||
|
|
|
|||
|
|
#### 第6题(多选):Docker 数据持久化
|
|||
|
|
|
|||
|
|
> [!CAUTION] 错题回顾
|
|||
|
|
> 你对 Docker Volume 和 Bind Mount 的区别还需要理清。
|
|||
|
|
|
|||
|
|
6.
|
|||
|
|
|
|||
|
|
【多选题】在使用Docker时,如何实现数据的持久化存储?(5分)
|
|||
|
|
|
|||
|
|
A. 通过配置 tmpfs 挂载
|
|||
|
|
|
|||
|
|
B. 使用 Docker Volume
|
|||
|
|
|
|||
|
|
C. 创建 Bind Mounts
|
|||
|
|
|
|||
|
|
D. 在容器内部使用外部存储设备
|
|||
|
|
|
|||
|
|
**正确答案:** BC
|
|||
|
|
**作答答案:** BD ❌
|
|||
|
|
|
|||
|
|
> [!THINK] 💡 tmpfs vs Volume vs Bind Mount
|
|||
|
|
> - **tmpfs 挂载**:存在宿主机内存中,容器重启后数据丢失 → ❌ 不是持久化
|
|||
|
|
> - **Docker Volume**:由 Docker 管理,存储在 `/var/lib/docker/volumes/`,容器删除后数据还在 → ✅
|
|||
|
|
> - **Bind Mounts**:绑定宿主机目录到容器,生命周期一致 → ✅
|
|||
|
|
> - 选 B 和 C
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第9题(多选):Protobuf 优势
|
|||
|
|
|
|||
|
|
> [!INFO] Protobuf 核心特性速查表
|
|||
|
|
> | 特性 | JSON | Protobuf |
|
|||
|
|
> |------|------|----------|
|
|||
|
|
> | 大小 | 较大(文本格式) | 小(二进制编码) |
|
|||
|
|
> | 解析速度 | 中等 | 快 |
|
|||
|
|
> | 人类可读 | ✅ | ❌(需 .proto 文件) |
|
|||
|
|
> | 向后兼容 | ✅ | ✅(靠 field number) |
|
|||
|
|
> | 跨语言 | ✅ | ✅ |
|
|||
|
|
|
|||
|
|
9.
|
|||
|
|
|
|||
|
|
【多选题】当需要在不同的应用程序之间传输数据时,使用 Protobuf 有哪些优势?(5分)
|
|||
|
|
|
|||
|
|
A. 数据压缩率高,节省存储空间
|
|||
|
|
|
|||
|
|
B. 直接可读,无需反序列化
|
|||
|
|
|
|||
|
|
C. 支持多种编程语言
|
|||
|
|
|
|||
|
|
D. 序列化过程速度快,对性能影响小
|
|||
|
|
|
|||
|
|
**正确答案:** ACD
|
|||
|
|
**作答答案:** AD ❌
|
|||
|
|
|
|||
|
|
> [!CAUTION] 为什么选 A 不选 B?
|
|||
|
|
> - **A 是对的**:Protobuf 二进制编码比 JSON 文本紧凑很多,尤其是数值类型用 varint 编码后更小
|
|||
|
|
> - **B 是错的**:Protobuf 是二进制格式,对人不可读,必须先反序列化才能得到结构化数据
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第10题(多选):Protobuf 序列化基础
|
|||
|
|
|
|||
|
|
> [!INFO] Protobuf 版本兼容性机制
|
|||
|
|
> Protobuf 通过 field number(字段编号)而非字段名来识别数据。添加新字段不影响旧客户端解析(向前兼容),删除旧字段不影响新客户端读取已有字段(向后兼容)。
|
|||
|
|
|
|||
|
|
10.
|
|||
|
|
|
|||
|
|
【多选题】在使用 Protobuf 进行序列化和反序列化时,以下哪些说法是正确的?(5分)
|
|||
|
|
|
|||
|
|
A. Protobuf 是一种轻量级的数据交换格式
|
|||
|
|
|
|||
|
|
B. Protobuf 只能用于 C++ 语言
|
|||
|
|
|
|||
|
|
C. Protobuf 版本支持向后兼容性和向前兼容性
|
|||
|
|
|
|||
|
|
D. Protobuf 的序列化格式比 JSON 小
|
|||
|
|
|
|||
|
|
**正确答案:** ACD
|
|||
|
|
**作答答案:** ACD ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第20题:Protobuf varint 编码
|
|||
|
|
|
|||
|
|
> [!INFO] Varint 编码原理
|
|||
|
|
> Protobuf 使用可变长度整数编码(varint),每个字节只用 7 位存储数据,最高位表示"是否还有后续字节"。小整数只需 1 个字节,大整数可能需要 2-5 个字节。相比固定长度的 int32/int64,在大多数场景下更省空间。
|
|||
|
|
|
|||
|
|
20.
|
|||
|
|
|
|||
|
|
【单选题】在解析 Protobuf 的数据时,为什么需要使用 varint 编码的整数?(5分)
|
|||
|
|
|
|||
|
|
A. 因为 varint 编码更节省空间,可以表示任意大小的整数。
|
|||
|
|
|
|||
|
|
B. 因为 varint 编码使整数的编码更简单。
|
|||
|
|
|
|||
|
|
C. 因为 varint 编码使数据解析更快。
|
|||
|
|
|
|||
|
|
D. 因为 varint 编码适合网络传输的不定长整数编码。
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** D ❌
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、Go 并发编程
|
|||
|
|
|
|||
|
|
### Goroutine 调度模型
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TB
|
|||
|
|
G[goroutines] --> S[Scheduler 调度器]
|
|||
|
|
S --> M[M threads]
|
|||
|
|
M --> W1["OS Thread 1 → g1, g3"]
|
|||
|
|
M --> W2["OS Thread 2 → g2, g4"]
|
|||
|
|
S -->|"协程切换开销 ~0.2μs"| P["⚡ 远轻于线程"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!INFO] goroutine vs 线程
|
|||
|
|
> goroutine 初始栈仅 2KB(可动态伸缩),而系统线程通常是几 MB。Go 的 M:N 调度器在少量 OS 线程上复用成千上万 goroutine,因此并发成本极低。
|
|||
|
|
|
|||
|
|
### 原题回顾
|
|||
|
|
|
|||
|
|
#### 第7题:goroutine 输出顺序
|
|||
|
|
|
|||
|
|
7.
|
|||
|
|
|
|||
|
|
【单选题】下列代码的输出结果是什么?(5分)
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
package main
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"fmt"
|
|||
|
|
"sync"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
func main() {
|
|||
|
|
var wg sync.WaitGroup
|
|||
|
|
for i := 0; i < 3; i++ {
|
|||
|
|
wg.Add(1)
|
|||
|
|
go func(i int) {
|
|||
|
|
defer wg.Done()
|
|||
|
|
fmt.Println(i)
|
|||
|
|
}(i) // 注意:传参确保每个 goroutine 拿到独立的 i
|
|||
|
|
}
|
|||
|
|
wg.Wait()
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
A. 打印 0 1 2,顺序不定
|
|||
|
|
|
|||
|
|
B. 打印三次 2
|
|||
|
|
|
|||
|
|
C. 编译错误
|
|||
|
|
|
|||
|
|
D. 打印顺序一定是 0 1 2
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
> [!THINK] 💡 关键细节
|
|||
|
|
> 虽然传了 `(i)` 参数避免了闭包共享变量问题(所以不会全打印 2),但三个 goroutine 是并发执行的,谁先抢到 CPU 时间片不确定,所以打印顺序不定。`wg.Wait()` 只保证等所有 goroutine 执行完,不规定顺序。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、Gin 框架
|
|||
|
|
|
|||
|
|
### Gin 上下文流转
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart LR
|
|||
|
|
Client[客户端请求] --> Handler[Handler 处理]
|
|||
|
|
Handler -->|"c.Set(key, val)"| Context["Gin Context\n(c.Get / c.ShouldBind)"]
|
|||
|
|
Context --> Next[中间件 / 下一个 Handler]
|
|||
|
|
Next --> Response[返回响应]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 原题回顾
|
|||
|
|
|
|||
|
|
#### 第6题:获取路由参数
|
|||
|
|
|
|||
|
|
> [!INFO] Gin 参数获取速查
|
|||
|
|
> | 方法 | 用途 | 示例 URL |
|
|||
|
|
> |------|------|----------|
|
|||
|
|
> | `c.Param("id")` | 路由参数 | `/users/:id` |
|
|||
|
|
> | `c.Query("page")` | Query 参数 | `/users?page=1` |
|
|||
|
|
> | `c.DefaultQuery("page", "1")` | Query + 默认值 | `/users` |
|
|||
|
|
> | `c.PostForm("name")` | Form 表单 | POST body |
|
|||
|
|
|
|||
|
|
6.
|
|||
|
|
|
|||
|
|
【单选题】在Gin框架中如何获取路由参数?(5分)
|
|||
|
|
|
|||
|
|
A. `c.Param("param_name")`
|
|||
|
|
|
|||
|
|
B. `c.GetQuery("param_name")`
|
|||
|
|
|
|||
|
|
C. `c.Params("param_name")`
|
|||
|
|
|
|||
|
|
D. `c.Query("param_name")`
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第18题:设置 JSON 响应
|
|||
|
|
|
|||
|
|
18.
|
|||
|
|
|
|||
|
|
【单选题】在Gin中如何设置响应格式为JSON?(5分)
|
|||
|
|
|
|||
|
|
A. `c.JSON(200, gin.H{"message": "ok"})`
|
|||
|
|
|
|||
|
|
B. `c.SetJSON(200, gin.H{"message": "ok"})`
|
|||
|
|
|
|||
|
|
C. `c.Response(200, "application/json", gin.H{"message": "ok"})`
|
|||
|
|
|
|||
|
|
D. `c.SendJSON(200, gin.H{"message": "ok"})`
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
> [!NOTE] Gin.H 的本质
|
|||
|
|
> `gin.H` 就是 `map[string]interface{}` 的类型别名,简洁写法。底层调用 `c.Status(code).Render(200, h)` 自动设置 `Content-Type: application/json`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、Docker Compose & 工程实践
|
|||
|
|
|
|||
|
|
### Dockerfile 层缓存优化
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart LR
|
|||
|
|
L1["COPY go.mod go.sum"] -->|"命中缓存 🟢"| L2["go mod download"]
|
|||
|
|
L2 -->|"源码变了 ✏️"| L3["COPY . ."]
|
|||
|
|
L3 -->|"编译 🔨"| L4["go build"]
|
|||
|
|
L1 -.|-| L2b["未命中 🟡\n依赖文件变了,重建缓存"]
|
|||
|
|
L2b --> L3b["COPY . ."]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!TIP] Dockerfile 分层缓存的黄金法则
|
|||
|
|
> **变化越少的层放前面,变化多的放后面**。这样大部分构建步骤可以直接复用缓存层,大幅提升构建速度。
|
|||
|
|
|
|||
|
|
### 多阶段构建对比
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart LR
|
|||
|
|
subgraph Before["单阶段构建 ❌"]
|
|||
|
|
B1["Go SDK + src + deps"] --> B2["Binary"]
|
|||
|
|
B_end["最终镜像 ≈ 800MB"]
|
|||
|
|
end
|
|||
|
|
subgraph After["多阶段构建 ✅"]
|
|||
|
|
A1["Builder Stage: Go SDK + src + deps"] --> A2["Binary"]
|
|||
|
|
A_end["Final Stage: Binary only\n≈ 20MB"]
|
|||
|
|
end
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 原题回顾
|
|||
|
|
|
|||
|
|
#### 第14题:Dockerfile 指令顺序
|
|||
|
|
|
|||
|
|
14.
|
|||
|
|
|
|||
|
|
【单选题】在Go服务的Dockerfile中,如何安排COPY指令和依赖安装指令顺序以最大程度利用缓存?(5分)
|
|||
|
|
|
|||
|
|
A. 先 COPY go.mod 和 go.sum,再执行依赖安装,然后再 COPY 源码
|
|||
|
|
|
|||
|
|
B. 全部文件一次性 COPY 到镜像后,统一安装依赖
|
|||
|
|
|
|||
|
|
C. 先安装依赖,再 COPY go.mod 和 go.sum
|
|||
|
|
|
|||
|
|
D. 先 COPY 源码,再 COPY go.mod 和 go.sum,然后安装依赖
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第15题:多阶段构建适用场景
|
|||
|
|
|
|||
|
|
15.
|
|||
|
|
|
|||
|
|
【单选题】在下列哪种场景下最推荐在 Dockerfile 中使用多阶段构建?(5分)
|
|||
|
|
|
|||
|
|
A. 需要从源代码构建应用,并且只需最终运行文件进镜像
|
|||
|
|
|
|||
|
|
B. 仅需将静态资源服务器部署到镜像
|
|||
|
|
|
|||
|
|
C. 部署单一配置文件到镜像,且无需编译
|
|||
|
|
|
|||
|
|
D. 基础镜像极小,且无需进一步处理
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第16题:多阶段构建的好处
|
|||
|
|
|
|||
|
|
16.
|
|||
|
|
|
|||
|
|
【单选题】在编写 Dockerfile 时,使用多阶段构建最主要的好处是什么?(5分)
|
|||
|
|
|
|||
|
|
A. 可以显著减小最终镜像的体积,避免无关构建文件被包含
|
|||
|
|
|
|||
|
|
B. 可以自动部署更新到生产环境
|
|||
|
|
|
|||
|
|
C. 能够让 Dockerfile 支持热重载代码
|
|||
|
|
|
|||
|
|
D. 可以让 Docker 镜像自动支持跨平台运行
|
|||
|
|
|
|||
|
|
**正确答案:** A
|
|||
|
|
**作答答案:** A ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第21题:Docker Compose 容器通信
|
|||
|
|
|
|||
|
|
> [!INFO] Docker Compose 内置 DNS
|
|||
|
|
> Compose 会自动为同一网络中的服务创建一个内部 DNS 服务器。服务名就是主机名,内部端口就是连接端口。
|
|||
|
|
|
|||
|
|
21.
|
|||
|
|
|
|||
|
|
【单选题】在同一个 docker-compose.yml 文件中定义了一个前端 nginx 服务和一个后端 go-api 服务(均未特别配置外部网络)。如果前端容器内的服务想要调用后端接口,最正确、最符合容器化工程实践的通信地址应该怎么写?(5分)
|
|||
|
|
|
|||
|
|
A. 必须通过宿主机的内网 IP 加上被映射出来的端口进行调用。
|
|||
|
|
|
|||
|
|
B. 必须在前端服务中使用 links: - go-api 指令后才能通信。
|
|||
|
|
|
|||
|
|
C. 直接使用后端服务在 YAML 中定义的服务名(即 go-api)作为域名,加上其容器内部端口号即可调用。
|
|||
|
|
|
|||
|
|
D. 前后端容器相互隔离,必须通过配置 Nginx 将后端暴露到外网后才能互相访问。
|
|||
|
|
|
|||
|
|
**正确答案:** C
|
|||
|
|
**作答答案:** C ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第22题:depends_on 指令
|
|||
|
|
|
|||
|
|
> [!WARNING] depends_on 的限制
|
|||
|
|
> `depends_on` 只保证**启动顺序**,不保证**就绪状态**。Redis 容器启动了 ≠ Redis 服务已准备好接受连接。如果需要等待就绪,应结合 `wait-for-it.sh` 或 Healthcheck 机制。
|
|||
|
|
|
|||
|
|
22.
|
|||
|
|
|
|||
|
|
【单选题】在一个包含 Go Web 服务和 Redis 缓存的微服务架构中,为了保证 Redis 容器在 Go 服务之前启动,应该在 Go 服务的配置中使用哪个指令?(5分)
|
|||
|
|
|
|||
|
|
A. `network_mode: redis`
|
|||
|
|
|
|||
|
|
B. `wait_for: redis`
|
|||
|
|
|
|||
|
|
C. `depends_on: - redis`
|
|||
|
|
|
|||
|
|
D. `links: - redis`
|
|||
|
|
|
|||
|
|
**正确答案:** C
|
|||
|
|
**作答答案:** B ❌
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第23题:Docker Compose 的核心作用
|
|||
|
|
|
|||
|
|
23.
|
|||
|
|
|
|||
|
|
【单选题】关于 Docker Compose 的主要作用和核心机制,以下说法最准确的是?(5分)
|
|||
|
|
|
|||
|
|
A. 它是一个用于打包单一 Docker 镜像的构建工具,类似于更高级的 Dockerfile。
|
|||
|
|
|
|||
|
|
B. 它是一个容器编排工具,主要用于定义和运行多容器的 Docker 应用程序,默认配置文件名为 docker-compose.yml。
|
|||
|
|
|
|||
|
|
C. 它是 Docker 官方提供的跨主机集群管理工具,专门用于生产环境的负载均衡。
|
|||
|
|
|
|||
|
|
D. 它只能用于管理无状态服务,无法处理需要挂载数据卷的数据库容器。
|
|||
|
|
|
|||
|
|
**正确答案:** B
|
|||
|
|
**作答答案:** B ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第2题(多选):加快镜像构建
|
|||
|
|
|
|||
|
|
> [!TIP] Docker 镜像构建提速清单
|
|||
|
|
> 1. ✅ 使用 `.dockerignore` 排除不必要的文件
|
|||
|
|
> 2. ✅ 合并 RUN 指令减少层级
|
|||
|
|
> 3. ✅ 利用缓存:将不变的依赖放在前面
|
|||
|
|
> 4. ✅ 多阶段构建减小最终体积
|
|||
|
|
> 5. ✅ 使用 `--mount=type=cache` 挂载 Go/npm 缓存目录
|
|||
|
|
|
|||
|
|
2.
|
|||
|
|
|
|||
|
|
【多选题】为了加快Docker镜像的构建速度,以下哪些操作是推荐的?(5分)
|
|||
|
|
|
|||
|
|
A. 使用多阶段构建来优化镜像
|
|||
|
|
|
|||
|
|
B. 在构建过程中,频繁变换基础镜像
|
|||
|
|
|
|||
|
|
C. 最大限度地利用已有层的缓存
|
|||
|
|
|
|||
|
|
D. 将不变的依赖放在Dockerfile的前面
|
|||
|
|
|
|||
|
|
**正确答案:** ACD
|
|||
|
|
**作答答案:** AD ❌
|
|||
|
|
|
|||
|
|
> [!THINK] 💡 为什么漏选 A?
|
|||
|
|
> 多阶段构建虽然主要目的是减小镜像体积,但也间接提升了构建效率——因为最终的产物更精简,构建步骤也更清晰。B 明显错误(频繁换基础镜像完全违背了缓存原则)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 八、Nginx & CDN
|
|||
|
|
|
|||
|
|
### Nginx 反向代理角色
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant User as 用户浏览器
|
|||
|
|
participant Nginx as Nginx 反向代理
|
|||
|
|
participant Go as Go 后端
|
|||
|
|
participant CDN as CDN 边缘节点
|
|||
|
|
User->>Nginx: HTTPS 请求 :80/443
|
|||
|
|
alt 静态资源
|
|||
|
|
Nginx->>CDN: 转发到最近边缘
|
|||
|
|
CDN-->>User: 静态内容
|
|||
|
|
else API 请求
|
|||
|
|
Nginx->>Go: 反向代理到内部端口
|
|||
|
|
Go-->>Nginx: JSON 响应
|
|||
|
|
Nginx-->>User: 返回响应
|
|||
|
|
end
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!INFO] 为什么前端要用 Nginx 挡一层?
|
|||
|
|
> - **统一入口**:SSL 终止、请求过滤、路由分发在一处完成
|
|||
|
|
> - **静态服务**:Nginx 处理静态文件的性能远超业务框架
|
|||
|
|
> - **安全**:隐藏后端真实 IP 和端口,便于集中做限流和黑白名单
|
|||
|
|
|
|||
|
|
### 原题回顾
|
|||
|
|
|
|||
|
|
#### 第17题:CDN 的工作原理
|
|||
|
|
|
|||
|
|
17.
|
|||
|
|
|
|||
|
|
【单选题】内容分发网络(CDN)如何帮助提高网站的加载速度?(5分)
|
|||
|
|
|
|||
|
|
A. 通过将网站流量全部重定向到一个特定的服务器节点
|
|||
|
|
|
|||
|
|
B. 通过在地理上分布的网站服务器上缓存内容来降低延迟
|
|||
|
|
|
|||
|
|
C. 通过增加网站的图像和视频质量
|
|||
|
|
|
|||
|
|
D. 通过限制用户访问内容的次数
|
|||
|
|
|
|||
|
|
**正确答案:** B
|
|||
|
|
**作答答案:** B ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第24题:Nginx 反向代理的意义
|
|||
|
|
|
|||
|
|
24.
|
|||
|
|
|
|||
|
|
【单选题】当我们的全栈项目要部署到生产环境时,通常会在最外层挡一个 Nginx,并将外部请求"反向代理"给内部的 Go 应用程序。为什么要多此一举,而不是直接让 Go 监听 80/443 端口对外提供服务?(5分)
|
|||
|
|
|
|||
|
|
A. 因为 Go 语言标准库的 net/http 性能太差,无法承受高并发,必须靠 Nginx 提速。
|
|||
|
|
|
|||
|
|
B. 因为 Go 程序无法处理 HTTPS 证书的加密解密。
|
|||
|
|
|
|||
|
|
C. Nginx 专精于静态文件的高效分发,并且能够作为统一入口隐藏后端真实 IP,还能轻松实现请求路由分发、负载均衡和限流,极大提升了整体架构的健壮性和安全性。
|
|||
|
|
|
|||
|
|
D. 这是操作系统的强制要求,所有的 Web 流量必须先经过 Nginx 才能到达用户态程序。
|
|||
|
|
|
|||
|
|
**正确答案:** C
|
|||
|
|
**作答答案:** C ✅
|
|||
|
|
|
|||
|
|
> [!NOTE] Go vs Nginx 的性能对比
|
|||
|
|
> Go 的 `net/http` 性能非常强(Go 1.21 压测可达百万级 QPS),不需要 Nginx 来"提速"。Nginx 在这里的价值在于**架构层面**的多路复用、静态处理和安全管理,而非纯吞吐量。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 九、HTTP 协议 & CORS
|
|||
|
|
|
|||
|
|
### CORS 工作流程
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TD
|
|||
|
|
A[前端页面 http://app.com:3000] -->|"普通请求 → 带 Origin 头"| B[后端 API http://api.com:8080]
|
|||
|
|
B -->|"同源 ✅ | 跨域 → 预检请求"| C{CORS 检查}
|
|||
|
|
C -->|"Access-Control-Allow-Origin 匹配"| D["✅ 允许,返回数据"]
|
|||
|
|
C -->|"不匹配 / 缺失"| E["❌ 浏览器拦截\nConsole 报 CORS error"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!CRITICAL] CORS 的本质
|
|||
|
|
> CORS 是**浏览器的安全机制**,不是服务器端的限制。服务器完全可以收到跨域请求并返回数据——只是浏览器看到缺少正确的 CORS 头就会拒绝把响应交给 JS。
|
|||
|
|
|
|||
|
|
### 原题回顾
|
|||
|
|
|
|||
|
|
#### 第19题:HTTP 状态码
|
|||
|
|
|
|||
|
|
> [!INFO] 常用 HTTP 状态码速记
|
|||
|
|
> | 状态码 | 含义 | 场景 |
|
|||
|
|
> |--------|------|------|
|
|||
|
|
> | 200 | OK | 请求成功 |
|
|||
|
|
> | 304 | Not Modified | 缓存命中,无需重新下载 |
|
|||
|
|
> | 301 / 302 | Moved / Found | 永久/临时重定向 |
|
|||
|
|
> | 401 | Unauthorized | 未认证 |
|
|||
|
|
> | 403 | Forbidden | 已认证但无权 |
|
|||
|
|
> | 404 | Not Found | 资源不存在 |
|
|||
|
|
> | 500 | Internal Server Error | 服务端错误 |
|
|||
|
|
|
|||
|
|
19.
|
|||
|
|
|
|||
|
|
【单选题】哪种HTTP状态码代表"未修改"?(5分)
|
|||
|
|
|
|||
|
|
A. 200 OK
|
|||
|
|
|
|||
|
|
B. 304 Not Modified
|
|||
|
|
|
|||
|
|
C. 404 Not Found
|
|||
|
|
|
|||
|
|
D. 500 Internal Server Error
|
|||
|
|
|
|||
|
|
**正确答案:** B
|
|||
|
|
**作答答案:** B ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第25题:Proxy 代理原理
|
|||
|
|
|
|||
|
|
25.
|
|||
|
|
|
|||
|
|
【单选题】在前端开发阶段,我们通常会在 vite.config.js 或 vue.config.js 中配置 proxy 代理来解决跨域问题。这个 Proxy 底层的运作逻辑是什么?(5分)
|
|||
|
|
|
|||
|
|
A. 它修改了浏览器的安全设置,让浏览器临时关闭了同源策略。
|
|||
|
|
|
|||
|
|
B. 它修改了前端发出的 HTTP 请求的 Origin,伪装成和后端同源。
|
|||
|
|
|
|||
|
|
C. 前端代码实际上把请求发给了 Vite 自带的本地 Node.js 开发服务器,开发服务器再把请求转发给真正的 Go 后端,最后把结果原样返回给前端。
|
|||
|
|
|
|||
|
|
D. 它自动为后端的 Go 代码注入了处理跨域的中间件。
|
|||
|
|
|
|||
|
|
**正确答案:** C
|
|||
|
|
**作答答案:** C ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第26题:CORS 报错的根本原因
|
|||
|
|
|
|||
|
|
> [!CAUTION] 高频面试考点
|
|||
|
|
> CORS 是前后端分离开发中最常见的痛点之一,也是面试必考题。记住关键词:"**同源策略 → 浏览器安全机制 → 阻止跨域响应读取**"。
|
|||
|
|
|
|||
|
|
26.
|
|||
|
|
|
|||
|
|
【单选题】前后端分离开发时,前端调用后端经常会遇到可怕的 CORS 报错。导致跨域报错的根本原因是什么?它为了解决什么痛点而存在?(5分)
|
|||
|
|
|
|||
|
|
A. 因为 HTTP 协议不允许不同端口之间通信,这是底层网络协议的限制。
|
|||
|
|
|
|||
|
|
B. 因为后端的 Go 代码默认开启了防火墙,拦截了来自其他端口的请求。
|
|||
|
|
|
|||
|
|
C. 这是浏览器的"同源策略 (Same-Origin Policy)"导致的,为了防止恶意网站窃取用户的敏感数据(如 Cookie),浏览器强制拦截了跨域的响应。
|
|||
|
|
|
|||
|
|
D. 因为前端框架(如 Vue/React)的安全机制,阻止了发起非同源的请求。
|
|||
|
|
|
|||
|
|
**正确答案:** C
|
|||
|
|
**作答答案:** C ✅
|
|||
|
|
|
|||
|
|
> [!THINK] 💡 如何在后端解决 CORS?
|
|||
|
|
> ```go
|
|||
|
|
> import "github.com/gin-contrib/cors"
|
|||
|
|
>
|
|||
|
|
> r.Use(cors.New(cors.Config{
|
|||
|
|
> AllowOrigins: []string{"http://localhost:3000"}, // 允许的前端地址
|
|||
|
|
> AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
|
|||
|
|
> AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},
|
|||
|
|
> AllowCredentials: true, // 携带 Cookie 时必须设为 true
|
|||
|
|
> MaxAge: 12 * time.Hour, // 预检请求缓存时间
|
|||
|
|
> }))
|
|||
|
|
> ```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十、JWT & Session
|
|||
|
|
|
|||
|
|
### Session vs JWT 对比
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart LR
|
|||
|
|
subgraph SessionAuth["Session 认证"]
|
|||
|
|
S1["客户端: 保存 SessionID (Cookie)"]
|
|||
|
|
S2["服务端: 存储用户数据<br/>Redis / 内存 / DB"]
|
|||
|
|
S3["⚠️ 集群环境下需要 Session 共享"]
|
|||
|
|
end
|
|||
|
|
subgraph JWTAuth["JWT 认证"]
|
|||
|
|
J1["客户端: 保存 JWT Token"]
|
|||
|
|
J2["服务端: 用私钥验证签名<br/>无需存储会话"]
|
|||
|
|
J3["✅ 天然无状态,水平扩展友好"]
|
|||
|
|
end
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Gin 中 JWT 信息传递流程
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TB
|
|||
|
|
Middleware["JWT 中间件\nParseString(bearer token)"] --> Valid{"Token 有效?"}
|
|||
|
|
Valid -->|否| Reject["返回 401 Unauthorized"]
|
|||
|
|
Valid -->|是| Set["c.Set claims.UserID / c.Set claims.Role"]
|
|||
|
|
Set --> Handler["业务 Handler\nc.Get claims.UserID"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!TIP] Gin Context 的正确用法
|
|||
|
|
> `c.Set` / `c.Get` 是基于 `context.Context` 的键值存储,生命周期限定在当前请求范围内,线程安全,是 Gin 中跨中间件和 Handler 传递信息的标准做法。
|
|||
|
|
|
|||
|
|
### 原题回顾
|
|||
|
|
|
|||
|
|
#### 第27题:JWT 解析后的最佳实践
|
|||
|
|
|
|||
|
|
> [!CAUTION] 错题回顾
|
|||
|
|
> 不要用 `c.Redirect` 来传递用户信息!Redirect 会中断当前请求流程,把用户带到另一个页面,这与"把用户信息传给后续 Handler"的需求完全不符。
|
|||
|
|
|
|||
|
|
27.
|
|||
|
|
|
|||
|
|
【单选题】当中间件成功解析并验证了前端请求头中的 JWT 令牌后,最佳的代码实践是?(5分)
|
|||
|
|
|
|||
|
|
中间件是查票员,查验完 JWT 后,通过 `c.Set()` 把乘客信息存储在当前 HTTP 请求的生命周期上下文中,后续函数可以安全、隔离地拿到用户信息。
|
|||
|
|
|
|||
|
|
A. 将解析出的用户 ID 保存到全局变量中。
|
|||
|
|
|
|||
|
|
B. 使用 `c.Redirect` 将请求重定向,并在 URL 参数里带上用户 ID。
|
|||
|
|
|
|||
|
|
C. 使用 `c.Set("userID", id)` 将用户信息存储在上下文中。
|
|||
|
|
|
|||
|
|
D. 将用户信息打包成 JSON 写回到响应体中,结束请求。
|
|||
|
|
|
|||
|
|
**正确答案:** C
|
|||
|
|
**作答答案:** B ❌
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第28题:JWT 解决的痛点
|
|||
|
|
|
|||
|
|
28.
|
|||
|
|
|
|||
|
|
【单选题】JWT 解决了传统 Session 架构的什么核心痛点?(5分)
|
|||
|
|
|
|||
|
|
JWT 是"无状态"的,服务端不需要存储会话记录就能验证其有效性,从而解决了传统 Session 在服务器集群环境下的共享与同步问题。
|
|||
|
|
|
|||
|
|
A. JWT 对用户密码进行了极强的加密,即便被黑客拦截也绝对安全。
|
|||
|
|
|
|||
|
|
B. 传统 Session 强依赖于服务端内存或集中存储,JWT 是"无状态"的。
|
|||
|
|
|
|||
|
|
C. JWT 生成的字符串非常短,比传统的 SessionID 更省网络带宽。
|
|||
|
|
|
|||
|
|
D. JWT 只能在 Go 语言和前端之间解析,跨语言安全性极高。
|
|||
|
|
|
|||
|
|
**正确答案:** B
|
|||
|
|
**作答答案:** B ✅
|
|||
|
|
|
|||
|
|
> [!NOTE] JWT ≠ 加密
|
|||
|
|
> JWT 默认是 Base64 编码(可读的),不包含加密。即使加了签名防止篡改,Token 内容本身仍然是明文的。因此**不要在 JWT 中存放敏感信息**(如密码、身份证号)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第29题:HttpOnly Cookie
|
|||
|
|
|
|||
|
|
> [!TIP] Cookie 安全防护体系
|
|||
|
|
> | 属性 | 作用 | 防御目标 |
|
|||
|
|
> |------|------|----------|
|
|||
|
|
> | `HttpOnly` | JavaScript 无法读取 | XSS 攻击 |
|
|||
|
|
> | `Secure` | 仅 HTTPS 传输 | 中间人窃听 |
|
|||
|
|
> | `SameSite` | 控制跨站发送 | CSRF 攻击 |
|
|||
|
|
> | `maxAge` | 过期时间 | 长期驻留风险 |
|
|||
|
|
|
|||
|
|
29.
|
|||
|
|
|
|||
|
|
【单选题】在使用 Gin 设置 Cookie 时,为了防止前端恶意脚本通过 JavaScript 读取到包含用户登录凭证的敏感 Cookie,你应该将哪个参数设置为什么值?(5分)
|
|||
|
|
|
|||
|
|
httpOnly 是防御 XSS 攻击的利器。当它设为 true 时,浏览器会把这个 Cookie 藏好,只有在向后端发送 HTTP 请求时才会默默带上,前端的任何 JS 代码都无权读取。顺便提一下,secure 也很重要,它表示该 Cookie 只能在 HTTPS 加密连接下传输,用来防止网络中间人窃听。
|
|||
|
|
|
|||
|
|
A. maxAge 设置为 0
|
|||
|
|
|
|||
|
|
B. secure 设置为 true
|
|||
|
|
|
|||
|
|
C. httpOnly 设置为 true
|
|||
|
|
|
|||
|
|
D. domain 设置为 "localhost"
|
|||
|
|
|
|||
|
|
**正确答案:** C
|
|||
|
|
**作答答案:** C ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 第30题:Gin 中 Session 的使用
|
|||
|
|
|
|||
|
|
30.
|
|||
|
|
|
|||
|
|
【单选题】关于 Gin 框架中 Session 的运用,以下说法正确的是?(5分)
|
|||
|
|
|
|||
|
|
Session 的本质是服务器在后端存储了用户状态,只把一个无意义的、随机的 SessionID 通过 Cookie 发给前端保存。Gin 核心库为了保持轻量,并没有内置 Session,推荐使用第三方中间件。
|
|||
|
|
|
|||
|
|
A. Gin 官方核心库自带了完善的 Session 管理器,无需引入第三方包。
|
|||
|
|
|
|||
|
|
B. Session 数据默认以明文形式保存在客户端的浏览器中。
|
|||
|
|
|
|||
|
|
C. Session 的本质是服务器在后端存储用户状态,只把 SessionID 发给前端。
|
|||
|
|
|
|||
|
|
D. 只要用户关闭浏览器页面,服务器端的 Session 数据就会被自动删除。
|
|||
|
|
|
|||
|
|
**正确答案:** C
|
|||
|
|
**作答答案:** C ✅
|
|||
|
|
|
|||
|
|
> [!INFO] Gin + Session 常见组合
|
|||
|
|
> ```go
|
|||
|
|
> // 常用第三方 Session 中间件
|
|||
|
|
> import "github.com/gin-contrib/sessions"
|
|||
|
|
> import "github.com/gin-contrib/sessions/redis"
|
|||
|
|
>
|
|||
|
|
> store, _ := redis.NewStore(10, "tcp", "localhost:6379", "", []byte("secret"))
|
|||
|
|
> r.Use(sessions.Sessions("session_name", store))
|
|||
|
|
> // 后续可通过 session.Get("user_id") 读取
|
|||
|
|
> ```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十一、多选题错题汇总
|
|||
|
|
|
|||
|
|
将所有做错的多选题汇总在此,方便集中复习:
|
|||
|
|
|
|||
|
|
| 题号 | 知识点 | 你的答案 | 正确答案 | 失分原因 |
|
|||
|
|
|------|--------|---------|---------|---------|
|
|||
|
|
| 单选-8 | 索引失效 | B | A | 未能识别函数对索引的影响 |
|
|||
|
|
| 多选-2 | Docker 构建加速 | AD | ACD | 漏选多阶段构建 |
|
|||
|
|
| 多选-3 | 慢查询措施 | ACD | ABCD | 排除了合理选项(硬件/存储过程) |
|
|||
|
|
| 多选-4 | 查询性能优化 | ABCD | ACD | 未排除"禁用外键"的错误选项 |
|
|||
|
|
| 多选-6 | Docker 持久化 | BD | BC | 混淆了 Volume/Bind Mount/tmfs |
|
|||
|
|
| 多选-7 | 查询优化方法 | ABCD | ABD | 误认为 ORM 能自动提升性能 |
|
|||
|
|
| 多选-8 | 索引优化因素 | ABCD | ABD | 忽略了索引对写入性能的影响 |
|
|||
|
|
| 多选-9 | Protobuf 优势 | AD | ACD | 未选"支持多种语言" |
|
|||
|
|
| 单选-22 | depends_on | B | C | 拼写了不存在的指令 |
|
|||
|
|
| 单选-27 | JWT 中间件 | B | C | 混淆了重定向与上下文传递 |
|
|||
|
|
| 单选-20 | Protobuf varint | D | A | 理解不够精准 |
|
|||
|
|
|
|||
|
|
> [!SUCCESS] 💪 复习建议
|
|||
|
|
> 从上面的表格可以看出,你的薄弱环节集中在:
|
|||
|
|
> 1. **MySQL 索引原理**(函数导致索引失效、索引对写入的影响)
|
|||
|
|
> 2. **Docker 概念辨析**(Volume vs tmpfs、depends_on 的作用)
|
|||
|
|
> 3. **Protobuf 特性**(多语言支持)
|
|||
|
|
> 下次考试前重点回顾这些模块的核心概念图。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 关联笔记
|
|||
|
|
|
|||
|
|
- [[Docker 容器与镜像]]
|
|||
|
|
- [[MySQL 索引优化]]
|
|||
|
|
- [[Gin 框架使用]]
|
|||
|
|
- [[JWT & Session 认证]]
|
|||
|
|
- [[Protobuf 入门]]
|
|||
|
|
- [[Nginx 反向代理]]
|
|||
|
|
- [[CORS 跨域解决方案]]
|