Docker和Nginx核心原理与实战:从环境隔离到反向代理、负载均衡
做运维这些年Docker 和 Nginx 这两个东西我几乎天天都在用。出去面试也好面试别人也好这两个工具几乎是绕不开的必考点。很多人会说“我会用 Docker 跑个容器”“我会配 Nginx 反代”但一问到“容器和虚拟机到底差在哪”“Nginx 凭什么能抗住高并发”这类核心原理问题就聊不下去了。其实是缺一套从底层原理往上长的知识体系而不是缺命令。这篇文章我想用一次从头到尾的扫盲式梳理把环境隔离、镜像分层、反向代理、负载均衡这些核心概念全部串到 Docker Nginx 这套组合拳里。无论是准备运维面试、考研复试、还是单纯想搞懂自己服务器上跑的东西是怎么work的这篇文章都能帮你把地基打牢。我把话放前面看完这篇文章你不仅知道怎么配还能讲清楚为什么这么配。1. 环境隔离Docker 到底在隔离什么1.1 容器和虚拟机差的不是一层壳很多人第一次接触 Docker 的时候都会有一个疑问它和 VMware、VirtualBox 这些虚拟机有什么区别我当年也绕了很久。简单说虚拟机是硬件级隔离虚拟出一个完整的操作系统包括内核而 Docker 容器是进程级隔离它不虚拟硬件直接复用宿主机的内核只是在用户空间上做了一层隔离。打个生活化的比方虚拟机就像你租了一整栋楼每户都是独立的水电、独立的墙体甚至能自己装修成不同风格装不同操作系统Windows、Linux 随便来而容器更像合租公寓大家都共用一栋楼的水管电路宿主机内核但每个房间有独立的门锁和卫生间命名空间隔离公共交通和公共区域有人管着分配控制组。因为容器共享宿主机内核所以它有几个非常明显的特点启动速度快到秒级、资源占用极低MB 级、一台物理机可以同时运行几十上百个容器。但也因此带来一个限制容器里的进程直接面对宿主机内核不能运行与宿主机不同内核版本的程序。比如你在 Linux 服务器上跑 Linux 容器没问题但想在 Linux 容器里跑 Windows 程序那是做不到的。1.2 命名空间和控制组隔离的两把钥匙Docker 容器能实现“看起来像一台独立服务器”的效果靠的是两个 Linux 内核特性Namespace命名空间和Cgroups控制组。Namespace 负责“看得见”什么Cgroups 负责“用得了多少”。我更愿意用一个比“合租公寓”更形象的例子来理解想象你在一个公寓里住你的房间有独立的锁PID Namespace让你只能看到自己的进程、独立的网络接口Network Namespace让你有自己的 IP 和端口、独立的根目录Mount Namespace让你访问自己的文件系统。实际上你还是住在公寓楼里但你看不见其他住户你的网络也是独立的这样就实现了“隔离”。具体来说Docker 使用的 Namespace 主要有这么几类Namespace 类型作用PID Namespace隔离进程编号容器内第一个进程 PID 是 1看不到宿主机其他进程Network Namespace隔离网络栈每个容器有自己的 IP、端口、路由表、防火墙规则Mount Namespace隔离文件系统挂载点容器有自己独立的根目录UTS Namespace隔离主机名和域名容器内 hostname 是独立的IPC Namespace隔离进程间通信资源比如消息队列、共享内存User Namespace隔离用户和用户组 ID让容器内 root 权限受限Cgroups 则是给容器设“使用上限”。比如一个容器最多用 1 核 CPU、512MB 内存这是通过 Cgroups 的 CPU 子系统、内存子系统、IO 子系统来实现的。当容器里的程序想“放飞自我”吃满所有内存时Cgroups 会先把它卡住防止把整个宿主机搞挂。这也是为什么 Docker 比裸机跑进程更稳定的原因之一——它天然给资源上了保险丝。1.3 镜像层、写时复制和联合文件系统Docker 的镜像和容器很多人分不清。我打个比方镜像就是做蛋糕的模具容器就是脱模之后的那个蛋糕。你可以用一个模具做很多个蛋糕每个蛋糕是独立的你可以在蛋糕上添奶油、加水果修改容器内容模具本身不会被破坏。镜像之所以能反复创建容器核心在于分层存储 写时复制。Docker 镜像是由一层一层的只读文件系统叠加而成的。每一层对应 Dockerfile 里的一条指令。比如 FROM nginx:latest 一层、COPY index.html /usr/share/nginx/html/ 一层、RUN apt-get install xxx 又一层。这些层是共享的多个镜像可以共用底层的基础层。当你用镜像创建容器时Docker 不会把整个镜像复制一份而是在最顶端加一个可写层容器层。你在容器里对文件的任何修改都会写在这个可写层里底层镜像完全不受影响。这就是“写时复制”的威力。下载镜像慢是每个新手都会遇到的头号痛点。我在后面 4.2 节给出了详细的加速方案这里先记住一个概念Docker Hub 的镜像仓库很多在国外国内直连速度感人需要配置镜像加速器这也是我自己踩了无数坑之后摸索出来的经验。2. Nginx 核心原理反向代理为什么是它的主场2.1 事件驱动模型和 worker 进程机制Nginx 之所以能成为高性能服务器的代表核心在于它的事件驱动模型。传统的 Apache 服务器一个请求来了往往要占用一个进程或线程去处理这种方式在高并发下会让内存和 CPU 迅速被吃光因为线程上下文切换的成本很高。Nginx 采用的是master-worker 多进程 事件驱动epoll架构。启动 Nginx 后你会看到有一个 master 进程它是老板负责读配置文件、管理 worker 进程下面还有好几个 worker 进程它们是干活的人每个 worker 进程都是一个独立的事件循环。当请求到达时worker 进程通过 epoll 机制同时监听成千上万个连接哪个连接有数据来了就处理谁没有数据就继续等待。这就像餐厅里一个服务员可以同时伺候二十桌客人不用每桌一直站着等上菜而是哪桌按铃了事件触发才过去服务。这种机制下Nginx 能用很小的内存轻松扛住几万甚至几十万的并发连接。我记得自己第一次压测 Nginx 的时候看到它轻轻松松扛住了 5 万并发连接而那个后端 Java 进程早已被压垮我才真正理解了它为什么叫“反向代理之王”。2.2 配置文件四大块和典型骨架Nginx 的配置文件通常是 nginx.conf看起来密密麻麻其实只要抓住结构就很好懂。它主要由四大块组成main全局块设置 worker 进程数、运行用户、PID 文件位置、日志级别等。events 块配置事件驱动模型比如每个 worker 进程维护的连接数上限。http 块HTTP 服务器全局配置比如 MIME 类型、默认日志格式、负载均衡 upstream 定义。server 块虚拟主机的配置一个 http 块里可以有多个 server每个 server 就是一个站点。location 块server 内部的路由匹配规则决定了不同 URL 路径怎么处理。我贴一份最常用的骨架配置把注释写清楚新手照着看能省不少时间worker_processes auto; # 自动适配 CPU 核心数一般设成核心数 events { worker_connections 1024; # 每个 worker 能同时维持的最大连接数 } http { include mime.types; # 内容类型映射表 default_type application/octet-stream; # 反向代理 负载均衡的服务器组 upstream backend_servers { server 172.18.0.2:8080 weight3; # 多台后端可以在这里扩展 server 172.18.0.3:8080 weight1; # weight 越大分配的请求越多 } server { listen 80; server_name example.com; # 静态文件直接由 Nginx 返回 location / { root /usr/share/nginx/html; index index.html; } # 动态请求转发给后端应用 location /api/ { proxy_pass http://backend_servers; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } }2.3 location 匹配规则别被优先级坑了location 的匹配规则经常是面试题里的重灾区也是实际排错时的隐形炸弹。它有好几种写法我列一个优先级从高到低的表格这个必须刻在脑子里匹配方式示例优先级精确匹配location /api/login最高前缀匹配带 ^~location ^~ /api/高正则匹配location ~ \.php$中普通前缀匹配location /api低默认匹配location /最低有几点我反复踩过的坑必须强调正则匹配区分大小写 ~ 和不区分大小写 ~*如果写错可能匹配不到 PHP 请求或者匹配到错误的后端。**优先匹配优先级最高的而不是匹配到第一个就停。**绝大多数新手以为 location /api/ 能挡住所有 /api 开头的请求但如果你后面写了正则location ~ \.json$请求/api/config.json会被正则“截胡”走因为正则匹配优先级在普通前缀之上。我看到有些生产事故就是这么引发的前端开发改了接口路径后端运维调了半天最后才发现是 location 优先级的问题。2.4 反向代理和负载均衡Nginx 的左膀右臂反向代理这个词听起来高深其实没有那么玄。它本质上是把客户端的请求转发给后端服务器再把后端返回的结果传回给客户端。如果想不通为什么 Nginx 能做反向代理试着这样理解它就是餐厅的前台客人不用直接找后厨点菜把菜单递给前台前台再把菜给后厨做。反向代理解决了几个非常实际的问题隐藏真实后端服务器 IP如果你有多台后端服务器客户端只知道 Nginx 的 IP不知道后端地址安全性更好。统一入口做负载均衡这是我最常用的场景。当业务量上来一台后端忙不过来就可以再部署几台通过 upstream 块配置多个后端地址Nginx 会根据负载均衡策略把请求分发到不同后端。承载静态资源动态请求转发给后端静态文件直接由 Nginx 返回后端应用压力能减轻一大截。负载均衡策略也有几种常用的我简单列一下策略说明适用场景轮询默认每个请求按顺序分配到不同后端后端配置基本相同weight 权重按权重分配性能好的机器配更大的 weight后端机器性能不一致ip_hash按客户端 IP 的哈希取模同一个 IP 固定在同一个后端需要会话保持但更推荐用 Redis 做会话共享least_conn总是分给当前连接数最少的后端长连接多、请求处理时间差异大3. Docker Nginx 组合实操3.1 快速跑一个 Nginx 容器并挂载网站目录先来一个最基础但也最经典的实战用 Docker 启动 Nginx并把宿主机上的网站目录挂载进容器。为什么用挂载而不是直接把文件 copy 进容器因为生产环境中你需要频繁更新代码挂载目录的话宿主机改文件容器立刻生效不需要重新 build 镜像。命令长这样docker run -d \ --name my-nginx \ -p 80:80 \ -v /home/www/my-site:/usr/share/nginx/html:ro \ -v /home/www/nginx-conf:/etc/nginx/conf.d:ro \ nginx:latest我拆解一下每个参数很多新手只知道照抄不知道丢了哪块就会出问题-d后台运行容器。--name my-nginx给容器起个名字后面docker exec或者docker stop都要用这个名字。-p 80:80端口映射。宿主机 80 端口映射到容器的 80 端口。如果你把冒号前的 80 改成 8080就是访问宿主机 8080 端口时映射到容器 80。-v /home/www/my-site:/usr/share/nginx/html:ro目录挂载。冒号前是宿主机路径冒号后是容器内路径:ro表示只读防止容器内误改宿主机文件。第二个挂载把自定义的 Nginx 配置目录挂到/etc/nginx/conf.d这样你新增站点配置不用进容器里改文件。启动后访问http://服务器IP/就能看到 Nginx 默认欢迎页或你自己的网站了。3.2 用 Nginx 容器反向代理宿主机的后端服务场景升级。现在宿主机 8080 端口跑着一个 Spring Boot 或 Java 服务你希望通过 Nginx 的 80 端口对外提供访问并且把/api/开头的请求转发给这个后端服务。这里有一个隐蔽的坑容器里的 Nginx 访问宿主机服务不能直接写127.0.0.1:8080。因为容器有自己独立的网络栈容器里的 127.0.0.1 指向容器自己而不是宿主机。正确的写法是在 Linux 上可以通过172.17.0.1Docker 默认网桥网关来访问宿主机或者在启动容器时加参数--add-hosthost.docker.internal:host-gateway然后配置里写proxy_pass http://host.docker.internal:8080;。在 Windows 和 macOS 的 Docker Desktop 中host.docker.internal已经内置了直接用。完整的配置我放在/home/www/nginx-conf/site.confserver { listen 80; server_name myapp.example.com; location /api/ { proxy_pass http://host.docker.internal:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }这里有一个细节我要专门讲一下proxy_pass后面的 URI 是否带斜杠会导致转发行为完全不一样。如果写proxy_pass http://host.docker.internal:8080;没有斜杠请求/api/login会完整转发给后端后端收到的路径还是/api/login。如果写proxy_pass http://host.docker.internal:8080/;带斜杠则/api/这一部分会被替换成/后端收到的路径是/login。这个点特别容易出问题。有一次我排查了整整一下午看到一个接口老是 404最后发现就是proxy_pass的斜杠写错了。所以读配置的时候一定要留意这一点。3.3 用 Docker Compose 编排 Nginx 和多个应用容器如果说上面是单兵作战那 Docker Compose 就是多容器集团军作战的模式。当你需要同时跑多个服务并且还要让它们之间互相通信时用docker run一条条敲命令就不太合适了。这个场景在实际生产中很常见也正好是目前招聘市场非常看重的能力。假设这样一个架构一个 Vue/React 前端静态资源由 Nginx 提供后端有两个 API 服务Nginx 需要把请求负载均衡到这两个后端服务。我直接用docker-compose.yml来定义整个系统version: 3.8 services: # 后端服务一 backend-1: image: my-app:latest container_name: backend-1 environment: - DB_HOSTmysql - DB_PORT3306 ports: - 8081:8080 networks: - app-net restart: always # 后端服务二 backend-2: image: my-app:latest container_name: backend-2 environment: - DB_HOSTmysql - DB_PORT3306 ports: - 8082:8080 networks: - app-net restart: always # Nginx 反向代理 静态资源 nginx: image: nginx:latest container_name: nginx ports: - 80:80 - 443:443 volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./www:/usr/share/nginx/html:ro - ./ssl:/etc/nginx/ssl:ro depends_on: - backend-1 - backend-2 networks: - app-net restart: always networks: app-net: driver: bridge核心是networks: app-net。在同一个自定义网络里的容器可以通过**服务名service name**互相访问。比如 Nginx 容器里配置反向代理直接写upstream backend_servers { server backend-1:8080 weight1; server backend-2:8080 weight1; }注意这里的backend-1和backend-2不是 IP 地址而是 Docker Compose 里的服务名Docker 内置的 DNS 会自动把这些服务名解析成对应的容器 IP。这比写死 IP 靠谱多了因为容器 IP 会变动服务名不会变。启动命令是docker compose up -d查看日志是docker compose logs -f停掉整个环境是docker compose down。这套流程熟悉之后部署一套完整环境基本就是几秒钟的事。3.4 前端项目部署、history 路由与 SSL 配置前端单页应用SPA和 Docker Nginx 组合是绝配。前端代码 build 完就是一堆静态文件丢进 Nginx 的 html 目录就完事。但有两个大坑必须在这里讲清楚。坑一history 路由模式。如果你用 HTML5 history 模式也就是 URL 里没有#的那种刷新某个子页面时Nginx 会去找/user/123这个路径结果发现没有这个文件返回 404。解决方法是配置try_fileslocation / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; }这行的意思是先尝试访问原始请求路径找不到就尝试将路径作为目录访问还找不到就统一返回 index.html由前端路由接管。坑二SSL 证书配置。证书文件放在容器里之后要保证 Nginx 能读到。通常我会建一个 ssl 目录把证书.crt或.pem和私钥.key放进去然后挂载到容器server { listen 443 ssl; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } } # HTTP 自动跳转 HTTPS server { listen 80; server_name example.com; return 301 https://$host$request_uri; }顺便说一下私钥文件格式需要注意的事情。搜索热词里有“nginx 支持哪种类型的私钥”这里统一解答Nginx 支持的私钥格式是 PEM 格式文件内容通常是-----BEGIN PRIVATE KEY-----或-----BEGIN RSA PRIVATE KEY-----开头的文本。如果你的私钥是 DER、PKCS12 或者 JKS 格式需要先用 OpenSSL 转换成 PEM 格式再放进 Nginx。如果你从证书供应商那儿下载的是.pfx或.p12文件需要用这条命令转换openssl pkcs12 -in yourfile.pfx -out nginx.pem -nodes证书链不完整也是个常见问题表现为浏览器提示“证书不受信任”。解决方法是把中间证书拼到主证书后面顺序是主证书在前、中间证书在后。4. 运维面试真题拆解与避坑指南4.1 高频面试八股参考答案写到这里我把面试中最容易出现的高频题整理了一个答题模板都是我在面试别人时经常问的也是被问过的。每个问题我给一个能拿分的回答思路不讲虚的Q1Docker 镜像和容器有什么区别镜像是一个只读的模板包含了运行应用所需的代码、运行时、系统库和配置容器是镜像运行时的实例相当于给镜像加了一个可写层。一个镜像可以创建多个容器容器之间有隔离。修改容器里的内容不会影响镜像但可以用docker commit把修改固化成一个新镜像。Q2Docker 如何实现环境隔离通过 Linux 的 Namespace 实现视图隔离进程、网络、文件系统、主机名等通过 Cgroups 实现资源限制CPU、内存、IO。它和虚拟机的区别在于容器共享宿主机内核而虚拟机有独立的完整内核。Q3反向代理和正向代理的区别是什么正向代理是为客户端代理隐藏的是客户端身份比如内网上网要通过代理服务器反向代理是为服务器代理隐藏的是后端服务器身份客户端只知道反向代理的地址不知道后端的真实地址。Nginx 主要作为反向代理使用比如把/api/请求转发给后端应用。Q4为什么 Nginx 能支撑高并发Nginx 采用多进程 事件驱动模型。每个 worker 进程通过 epoll 监听成千上万个连接有事件才处理不阻塞等待。与 Apache 的进程/线程模型相比它避免了每请求一进程的上下文切换开销内存占用小并发能力强。Q5Nginx 有哪些负载均衡策略轮询、加权轮询、ip_hash、least_conn 等。轮询适合后端性能一致加权轮询适合后端机器配置有差异ip_hash 可以让同一个客户端 IP 总是请求同一个后端适合需要本地会话但没做共享 Session 的旧系统。Q6proxy_pass不带斜杠和带斜杠有什么区别这个我在 3.2 节已经详细讲过。不带斜杠是完整路径转发带斜杠会替换掉匹配的 location 前缀。回答这个问题时如果能现场举一个例子面试官会认为你是真在自己动手配过的。Q7如何查看容器日志如何进入容器内部docker logs -f 容器名实时查看容器日志docker exec -it 容器名 bash进入容器执行命令。容器里没有 bash 就用 sh。Q8容器运行后如何修改 Nginx 配置推荐使用挂载配置文件的方式宿主机改完配置后执行docker exec 容器名 nginx -s reload热加载。如果没有挂载也可以先docker cp把配置复制进容器再 reload但重启容器后配置会丢失所以生产方式还是得挂载。以上这些如果都能脱口而出面试的口碑基本就稳了。4.2 镜像下载慢、403、502、404 等常见问题排查搜热词榜单里出现了“docker镜像下载慢”“prowlaar反向代理403”“nginx反向代理403”这几项说明这些确实是高频困扰。我把它们放到一起彻底讲一下。镜像下载慢怎么破最有效的办法是配置镜像加速器。在/etc/docker/daemon.json中可以把镜像加速地址配置到registry-mirrors下。国内各大云厂商都有自己的容器镜像加速服务每个账号会分配专属加速地址申请后配置进去就行。配置完记得执行systemctl restart docker重启 Docker 服务让配置生效。{ registry-mirrors: [https://你的专属镜像加速地址] }如果你找不到可用的镜像加速地址还有一个应急方案找一台能流畅访问 Docker Hub 的跳板机在上面执行docker pull nginx然后使用docker save -o nginx.tar nginx:latest导出镜像再传输到目标服务器用docker load -i nginx.tar导入。这种方式虽然笨但在极端情况下能救命。反向代理 403 是怎么来的403 最常见的原因有三个第一目录权限不对。Nginx worker 进程对网站目录没有读取权限特别是当你把/home/xxx这种目录挂载给 Nginx 容器时而宿主机上目录的属主和权限是700Nginx 的 worker 进程跑在容器内部UID 通常是 101nginx 用户读不到宿主机属主家的目录。解决方法是给网站目录设置755或静默 755或者把目录属主改成容器内 Nginx 的 UID。第二索引文件不存在。访问/时Nginx 自动去找 index.html 或 index.php找不到就会返回 403 Forbidden。解决方法是检查 root 目录下是否有正确的索引文件。第三配置了deny规则或授权问题。有些配置里加了 IP 黑名单、allow/deny规则如果客户端 IP 不在允许范围也会 403。502 Bad Gateway 怎么排查502 表示 Nginx 成功接收了请求但后端没有给出有效响应。排查路径很固定先看后端进程是否存活再看 Nginx 配置里的proxy_pass地址是否能连通用 curl 从 Nginx 容器里测试再看后端服务的日志。我遇到最多的情况是后端服务换了端口、容器重启后 IP 变了但 Nginx 配置还写死旧 IP。如果你用了 Docker Compose 的服务名访问这个问题就基本能避免。4.3 一份实用的容器运维工具箱最后这部分已经不是面试内容了纯粹是我个人在实际运维中沉淀下来的经验。如果你打算在生产环境真正使用 Docker Nginx下面这些细节一个都别忽略。日志处理。Nginx 的访问日志默认直接输出到标准输出stdout可以通过docker logs看到。但为了持久化我习惯把日志挂载到宿主机目录-v /var/log/nginx:/var/log/nginx同时用 logrotate 做日志轮转不然时间长了日志文件会撑爆磁盘。Nginx 镜像本身自带 logrotate 配置但如果你把日志挂载到宿主机宿主机的 logrotate 也要同步配置否则这段时间的日志没人管。健康检查与自愈。容器被强制杀掉后如果启动时没有加--restart always就不会自动拉起。生产环境我的统一标准是--restart always或者 compose 里的restart: always。另外可以给 Nginx 容器配置健康检查用 curl 探测默认网站是否返回 200healthcheck: test: [CMD, curl, -f, http://localhost/] interval: 30s timeout: 5s retries: 3资源限制。在容器启动时务必加资源限制防止某个异常容器吃满宿主机所有 CPU 和内存。Docker run 的常用参数是docker run -d \ --name my-nginx \ --cpus1.0 \ --memory512m \ nginx:latest时区问题。容器默认时区是 UTC世界标准时间如果你发现 Nginx 日志里的时间和本地时间差了 8 个小时那不是 Nginx 的 bug而是容器时区没有设置。解决方法是挂载/etc/localtime或通过环境变量TZAsia/Shanghai设置时区。多项目目录挂载。热词里提到“docker安装nginx并挂载多个项目目录”这个很实用。如果一台服务器上跑了好几个前端项目更优雅的方式不是一个目录挂载整个 Nginx 的 html而是分别挂载到不同目录再用多个 server 块路由。比如-v /home/www/project-a:/usr/share/nginx/html/a:ro -v /home/www/project-b:/usr/share/nginx/html/b:ro然后在 Nginx 配置里分别配置location /a/ { alias /usr/share/nginx/html/a/; }和location /b/ { alias /usr/share/nginx/html/b/; }。还有一个细节root和alias的区别一定要搞懂。root会把 location 的路径拼接到 root 后面找文件alias不会拼接直接把请求路径替换成 alias 指定的路径。如果配置成root /usr/share/nginx/html/a/请求/a/index.html时实际找的是/usr/share/nginx/html/a/a/index.html这会直接 404。很多人一上来就全用 root结果踩了这个坑。说实话Docker 和 Nginx 这两个东西单独拿出来任何一个都能写一本书。实际上也确实有书。但运维面试的核心从来不在于你背了多少命令而在于你能不能把一个看似简单的概念讲透让你部署的东西在出了问题时知道自己应该如何排查。我面试过不少做了两三年运维的候选人最大的差距往往不是工具熟练度而是对底层机制的理解深度。如果你准备面试我最后给一个建议不要只背命令而是要亲手搭一套环境把容器网络、端口映射、数据卷挂载、反向代理、负载均衡这几个点全部玩一遍遇到 502、403、404 就自己排查一遍。这个过程远比你刷一百篇博客有用。等你亲手把这些问题都解决过一遍之后面试官问什么你心里都是有底的。