nginx语法解析
- [Nginx 配置文件超详细解读](#Nginx 配置文件超详细解读)
-
- 一、全局块(第1-5行)
-
- [user nginx;](#user nginx;)
- [worker_processes auto;](#worker_processes auto;)
- [error_log /var/log/nginx/error.log notice;](#error_log /var/log/nginx/error.log notice;)
- [pid /var/run/nginx.pid;](#pid /var/run/nginx.pid;)
- [二、events 块(第7-9行)](#二、events 块(第7-9行))
-
- [worker_connections 1024;](#worker_connections 1024;)
- [三、http 块(第11-43行)](#三、http 块(第11-43行))
-
- [include /etc/nginx/mime.types;](#include /etc/nginx/mime.types;)
- [default_type application/octet-stream;](#default_type application/octet-stream;)
- [log_format main '...'](#log_format main '...')
- [access_log /var/log/nginx/access.log main;](#access_log /var/log/nginx/access.log main;)
- [sendfile on;](#sendfile on;)
- [#tcp_nopush on;](#tcp_nopush on;)
- [keepalive_timeout 65;](#keepalive_timeout 65;)
- [#gzip on;](#gzip on;)
- [四、server 块(虚拟主机)](#四、server 块(虚拟主机))
-
- [server { ... }](#server { ... })
- [listen 80;](#listen 80;)
- [server_name localhost;](#server_name localhost;)
- [五、location 块(路由规则)- 最重要!](#五、location 块(路由规则)- 最重要!)
-
- [location / { ... }](#location / { ... })
- [root /usr/share/nginx/html;](#root /usr/share/nginx/html;)
- [index index.html index.htm;](#index index.html index.htm;)
- [try_files uri uri/ /index.html;(最关键!)](#try_files uri uri/ /index.html;(最关键!))
- 六、错误页面配置
-
- [error_page 500 502 503 504 /50x.html;](#error_page 500 502 503 504 /50x.html;)
- [location = /50x.html { ... }](#location = /50x.html { ... })
- 七、配置块层级总结
- 八、项目的配置
- [拓展 - Web 核心概念详解](#拓展 - Web 核心概念详解)
-
- 概念一:静态托管
- 概念二:单页应用(SPA)
-
- [传统网站 vs 单页应用](#传统网站 vs 单页应用)
- 生活比喻
- [为什么你的 Vue 项目是单页应用?](#为什么你的 Vue 项目是单页应用?)
- [为什么需要 `try_files` 配置?](#为什么需要
try_files配置?)
- 概念三:反向代理
- 概念四:负载均衡
- 概念五:HTTPS
- 概念六:跨域(CORS)
- 概念七:限流
- 总结:一张图理解所有概念
- 对应你项目的情况
Nginx 配置文件超详细解读
为了方便日后查阅,我就以我项目中的 nginx.conf 为例,进行讲解:
conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
一、全局块(第1-5行)
user nginx;
作用:指定 Nginx 以哪个用户身份运行
比喻:公司规定,这个员工用什么工牌上班
详解:
- nginx 是一个 Linux 用户名
- 为什么要指定用户?出于安全考虑
- 不用 root 用户,是因为 root 权限太大,万一被黑客攻击,损失更大
- 用一个权限有限的用户更安全
worker_processes auto;
作用:开启几个工作进程
比喻:餐厅雇佣几个服务员
详解:
- auto = 自动根据 CPU 核心数决定
- 如果你的服务器是 4 核 CPU,就会开 4 个进程
- 每个进程独立工作,互不干扰
- 进程越多,能同时处理的请求越多
可选值:
- auto(推荐)
- 具体数字,如 4、8
error_log /var/log/nginx/error.log notice;
作用:错误日志保存在哪里,记录什么级别的错误
比喻:投诉记录本放在哪里,记录什么程度的投诉
详解:
- /var/log/nginx/error.log 是文件路径
- notice 是日志级别
日志级别(从低到高):
┌─────────┬────────────────────────────┐
│ 级别 │ 记录内容 │
├─────────┼────────────────────────────┤
│ debug │ 调试信息(最详细,最多) │
│ info │ 一般信息 │
│ notice │ 值得注意的信息 │
│ warn │ 警告 │
│ error │ 错误 │
│ crit │ 严重错误(最少) │
└─────────┴────────────────────────────┘
级别越高,记录的内容越少,文件越小
生产环境通常用 warn 或 error
pid /var/run/nginx.pid;
作用:记录 Nginx 主进程的进程号(PID)
比喻:员工工号记录在哪个文件里
详解:
- 这个文件里只有一个数字,比如 "12345"
- 其他程序可以通过读这个文件,知道 Nginx 的进程号
- 用于停止、重启 Nginx 时找到正确的进程
二、events 块(第7-9行)
nginx
events {
worker_connections 1024;
}
worker_connections 1024;
作用:每个工作进程最多能同时处理多少个连接
比喻:每个服务员最多同时服务多少桌客人
详解:
- 1024 表示每个进程最多 1024 个连接
- 总连接数 = worker_processes × worker_connections
- 如果 4 个进程,每个 1024,总共最多 4096 个同时连接
实际计算:
┌──────────────────────────────────────────┐
│ 4 个进程 × 1024 连接 = 4096 最大连接 │
│ │
│ 一般网站足够了 │
│ 高并发网站可以调到 65535 │
└──────────────────────────────────────────┘
三、http 块(第11-43行)
http 块是最重要的部分,配置 HTTP 服务的所有内容。
include /etc/nginx/mime.types;
作用:引入文件类型映射表
比喻:引入一本"文件类型字典"
详解:
- mime.types 文件里定义了文件扩展名和内容类型的对应关系
- 比如:
.html → text/html
.css → text/css
.js → application/javascript
.png → image/png
.jpg → image/jpeg
为什么需要?
- 浏览器需要知道文件类型才能正确处理
- 比如 .css 文件要当成样式表解析
- 如果类型错了,浏览器可能无法正常显示
default_type application/octet-stream;
作用:如果文件类型未知,默认当什么类型处理
比喻:如果字典里查不到,就当成"未知物品"处理
详解:
- application/octet-stream 表示"二进制流"
- 意思是:不知道是啥,就当成普通文件下载
- 浏览器遇到这种类型,会弹出下载框
log_format main '...'
作用:定义访问日志的格式
比喻:设计来客登记表的格式
详解:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
这里定义了一个叫 "main" 的日志格式:
┌────────────────────────┬─────────────────────────────────┐
│ 变量 │ 含义 │
├────────────────────────┼─────────────────────────────────┤
│ $remote_addr │ 访客的 IP 地址 │
│ $remote_user │ 访客用户名(通常是 -) │
│ $time_local │ 访问时间 │
│ $request │ 请求内容(如 GET /index.html) │
│ $status │ HTTP 状态码(200、404 等) │
│ $body_bytes_sent │ 发送的字节数 │
│ $http_referer │ 从哪个页面跳转来的 │
│ $http_user_agent │ 浏览器信息 │
│ $http_x_forwarded_for │ 代理链中的真实 IP │
└────────────────────────┴─────────────────────────────────┘
实际日志长这样:
192.168.1.100 - - [04/Feb/2026:10:30:00 +0800] "GET /index.html HTTP/1.1" 200 1234 "-" "Mozilla/5.0..."
access_log /var/log/nginx/access.log main;
作用:访问日志保存在哪里,用什么格式
比喻:来客登记表放在哪里,用哪种表格
详解:
- /var/log/nginx/access.log 是文件路径
- main 是上面定义的日志格式名称
每个人访问你的网站,都会在这个文件里留下一条记录
sendfile on;
作用:开启高效文件传输模式
比喻:开启"快速传菜通道"
详解:
┌─────────────────────────────────────────────────────────┐
│ sendfile off(关闭): │
│ 磁盘 → 内核缓冲区 → 用户空间 → 内核缓冲区 → 网络 │
│ (数据要复制好几次,慢) │
├─────────────────────────────────────────────────────────┤
│ sendfile on(开启): │
│ 磁盘 → 内核缓冲区 → 网络 │
│ (数据只复制一次,快) │
└─────────────────────────────────────────────────────────┘
结论:永远开启,没有理由关闭
#tcp_nopush on;
作用:优化网络传输(被注释掉了,没启用)
详解:
- # 开头表示注释,这行不生效
- tcp_nopush 开启后,会把小数据包攒在一起发送
- 减少网络包数量,提高效率
- 通常和 sendfile 一起使用效果更好
keepalive_timeout 65;
作用:保持连接的超时时间(秒)
比喻:客人点完餐后,服务员等他 65 秒再去服务下一桌
详解:
┌─────────────────────────────────────────────────────────┐
│ 没有 keepalive: │
│ 请求1 → 建立连接 → 传输 → 断开连接 │
│ 请求2 → 建立连接 → 传输 → 断开连接(每次都要重新连接) │
├─────────────────────────────────────────────────────────┤
│ 有 keepalive: │
│ 请求1 → 建立连接 → 传输 │
│ 请求2 → 复用连接 → 传输 │
│ 请求3 → 复用连接 → 传输 │
│ ...65秒没有新请求... → 断开连接 │
└─────────────────────────────────────────────────────────┘
好处:减少建立连接的开销,提高性能
#gzip on;
作用:开启压缩(被注释掉了,没启用)
详解:
- 开启后,会把文件压缩后再传输
- 比如 100KB 的 JS 文件,压缩后可能只有 30KB
- 传输更快,节省带宽
为什么注释掉?
- 可能是为了简单起见
- 生产环境建议开启
四、server 块(虚拟主机)
nginx
server {
listen 80;
server_name localhost;
...
}
server { ... }
作用:定义一个虚拟主机(网站)
比喻:定义餐厅里的一个"独立包间"
详解:
- 一个 Nginx 可以同时运行多个网站
- 每个 server 块就是一个网站
- 通过不同的端口或域名区分
例如:
server {
server_name www.site1.com; # 网站1
}
server {
server_name www.site2.com; # 网站2
}
server {
listen 8080; # 网站3(不同端口)
}
listen 80;
作用:监听哪个端口
比喻:餐厅开在哪条街的几号门
详解:
- 80 是 HTTP 的默认端口
- 443 是 HTTPS 的默认端口
- 浏览器访问 http://example.com 时,默认用 80 端口
- 所以 http://example.com 等于 http://example.com:80
其他写法:
listen 80; # 监听所有 IP 的 80 端口
listen 127.0.0.1:80; # 只监听本机
listen 443 ssl; # 监听 443 并启用 HTTPS
listen 80 default_server; # 设为默认网站
server_name localhost;
作用:这个网站响应哪个域名
比喻:餐厅的名字叫什么
详解:
- localhost 表示本机
- 可以配置实际域名,如 www.example.com
- 可以配置多个,用空格分隔
例如:
server_name www.example.com example.com; # 两个域名指向同一网站
server_name *.example.com; # 通配符,匹配所有子域名
server_name ~^www\d+\.example\.com$; # 正则表达式
访问流程:
用户输入 www.example.com
↓
DNS 解析到服务器 IP
↓
请求到达 Nginx
↓
Nginx 看 Host 头,找到匹配的 server_name
↓
由对应的 server 块处理
五、location 块(路由规则)- 最重要!
nginx
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location / { ... }
作用:匹配 URL 路径,决定如何处理请求
比喻:根据客人要去的楼层,决定走哪部电梯
详解:
location 后面的 / 表示匹配所有路径
不同的匹配规则:
┌──────────────┬─────────────────────────────────────────┐
│ 写法 │ 匹配规则 │
├──────────────┼─────────────────────────────────────────┤
│ location / │ 匹配所有路径(兜底) │
│ location /api│ 匹配以 /api 开头的路径 │
│ location = / │ 精确匹配,只匹配 / │
│ location ^~ /static │ 前缀匹配,优先级高 │
│ location ~ \.php$ │ 正则匹配(区分大小写) │
│ location ~* \.(jpg|png)$ │ 正则匹配(不区分大小写) │
└──────────────┴─────────────────────────────────────────┘
root /usr/share/nginx/html;
作用:网站文件存放的根目录
比喻:食材仓库在哪里
详解:
- 当用户访问 http://localhost/index.html
- Nginx 会去 /usr/share/nginx/html/index.html 找文件
- 当用户访问 http://localhost/css/style.css
- Nginx 会去 /usr/share/nginx/html/css/style.css 找文件
计算公式:
实际文件路径 = root + 请求路径
例如:
root = /var/www/html
请求 = /images/logo.png
实际 = /var/www/html/images/logo.png
index index.html index.htm;
作用:默认首页文件名
比喻:客人说"我要进门",默认带他去大厅
详解:
- 当用户访问目录(如 http://localhost/)
- Nginx 会按顺序查找:
1. 先找 index.html
2. 找不到再找 index.htm
3. 都找不到就报错
可以设置多个,按顺序查找:
index index.html index.htm default.html;
try_files uri uri/ /index.html;(最关键!)
作用:按顺序尝试查找文件,都找不到就用最后一个
比喻:
1. 先看客人要的菜有没有
2. 没有的话看看是不是套餐
3. 都不是就给他推荐招牌菜
详解:
$uri = 用户请求的路径(如 /about)
$uri/ = 把路径当目录查找(如 /about/index.html)
/index.html = 最终兜底方案
流程图:
用户访问 /about
↓
1、找 /usr/share/nginx/html/about 文件
↓ 找不到
2、找 /usr/share/nginx/html/about/index.html 文件
↓ 找不到
3、返回 /usr/share/nginx/html/index.html
↓
Vue Router 接管,显示 /about 页面
为什么 Vue 项目需要这个?
┌─────────────────────────────────────────────────────────┐
│ Vue 是单页应用(SPA),只有一个 index.html │
│ /login、/about、/user 这些"页面"其实都不存在 │
│ 都是由 Vue Router 在前端渲染出来的 │
│ │
│ 没有 try_files: │
│ 访问 /login → 404 Not Found(因为没有 login 文件) │
│ │
│ 有 try_files: │
│ 访问 /login → 找不到 → 返回 index.html → Vue 渲染 │
└─────────────────────────────────────────────────────────┘
六、错误页面配置
nginx
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
error_page 500 502 503 504 /50x.html;
作用:当发生这些错误时,显示指定页面
比喻:出了问题时,给客人看道歉信
详解:
500 = Internal Server Error(服务器内部错误)
502 = Bad Gateway(网关错误,通常是后端挂了)
503 = Service Unavailable(服务不可用)
504 = Gateway Timeout(网关超时)
当出现这些错误时,不显示默认的丑陋错误页面
而是显示你自定义的 /50x.html 页面
location = /50x.html { ... }
作用:精确匹配 /50x.html 这个路径
详解:
- = 表示精确匹配,必须完全相等
- 只有访问 /50x.html 才会匹配
- /50x.html?a=1 不匹配
- /50x.html/ 不匹配
这里指定了错误页面文件的位置
七、配置块层级总结
nginx.conf 结构图:
┌─────────────────────────────────────────────────────────┐
│ nginx.conf │
│ ┌───────────────────────────────────────────────────┐ │
│ │ 全局块 │ │
│ │ - user nginx │ │
│ │ - worker_processes auto │ │
│ │ - error_log ... │ │
│ │ - pid ... │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ events 块 │ │
│ │ - worker_connections 1024 │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ http 块 │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ http 全局配置 │ │ │
│ │ │ - include mime.types │ │ │
│ │ │ - sendfile on │ │ │
│ │ │ - keepalive_timeout 65 │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ server 块(网站1) │ │ │
│ │ │ - listen 80 │ │ │
│ │ │ - server_name localhost │ │ │
│ │ │ ┌───────────────────────────────────────┐ │ │ │
│ │ │ │ location / { ... } │ │ │ │
│ │ │ └───────────────────────────────────────┘ │ │ │
│ │ │ ┌───────────────────────────────────────┐ │ │ │
│ │ │ │ location /api { ... } │ │ │ │
│ │ │ └───────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ server 块(网站2) │ │ │
│ │ │ ... │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
八、项目的配置
| 行号 | 配置 | 作用 | 是否必须 |
|---|---|---|---|
| 1 | user nginx |
运行用户 | 推荐 |
| 2 | worker_processes auto |
工作进程数 | 必须 |
| 4 | error_log ... |
错误日志 | 推荐 |
| 5 | pid ... |
进程号文件 | 必须 |
| 8 | worker_connections 1024 |
最大连接数 | 必须 |
| 12 | include mime.types |
文件类型 | 必须 |
| 13 | default_type ... |
默认类型 | 推荐 |
| 15-17 | log_format ... |
日志格式 | 可选 |
| 19 | access_log ... |
访问日志 | 推荐 |
| 21 | sendfile on |
高效传输 | 推荐 |
| 24 | keepalive_timeout 65 |
保持连接 | 推荐 |
| 29 | listen 80 |
监听端口 | 必须 |
| 30 | server_name localhost |
域名 | 必须 |
| 33 | root ... |
文件目录 | 必须 |
| 34 | index ... |
默认首页 | 必须 |
| 35 | try_files ... |
SPA 关键 | Vue 必须 |
| 38-40 | error_page ... |
错误页面 | 可选 |
现在你应该对配置文件的每一部分都有了清晰的理解!有任何具体的配置项还不明白的,随时问我。
我是 Claude Opus 4.5 模型。
没关系!这些概念确实比较抽象,让我用最通俗的大白话,一个一个给你讲清楚。
拓展 - Web 核心概念详解
概念一:静态托管
什么是"静态"?
┌─────────────────────────────────────────────────────────┐
│ │
│ 【静态文件】= 写死的、不会变的文件 │
│ │
│ 比如: │
│ - HTML 文件(网页骨架) │
│ - CSS 文件(网页样式) │
│ - JS 文件(网页交互) │
│ - 图片(.png, .jpg) │
│ - 字体文件 │
│ │
│ 特点:你写什么,用户看到的就是什么,不会变 │
│ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ │
│ 【动态内容】= 根据情况变化的内容 │
│ │
│ 比如: │
│ - 用户登录后显示的用户名 │
│ - 购物车里的商品数量 │
│ - 数据库查询出来的文章列表 │
│ │
│ 特点:需要后端程序实时计算/查询 │
│ │
└─────────────────────────────────────────────────────────┘
什么是"托管"?
托管 = 把文件放到服务器上,让别人能访问
生活比喻:
┌─────────────────────────────────────────────────────────┐
│ │
│ 你写了一本书(你的网站代码) │
│ ↓ │
│ 放到图书馆(服务器) │
│ ↓ │
│ 别人可以来借阅(访问你的网站) │
│ │
│ "静态托管" = 图书馆帮你保管书,别人来了直接给他看 │
│ │
└─────────────────────────────────────────────────────────┘
静态托管的工作流程
你的电脑 服务器(Nginx) 用户浏览器
│ │ │
│ npm run build │ │
│ 生成 dist 文件夹 │ │
│ │ │ │
│ └──────上传────────→│ │
│ │ 保存在 │
│ │ /usr/share/nginx/html │
│ │ │
│ │←───── 请求 index.html ─────│
│ │ │
│ │────── 返回文件内容 ────────→│
│ │ │
│ │←───── 请求 style.css ──────│
│ │ │
│ │────── 返回文件内容 ────────→│
一句话总结:静态托管就是把你写好的网页文件放到服务器上,让别人能通过网址访问。
概念二:单页应用(SPA)
传统网站 vs 单页应用
【传统网站】(多页应用)
用户点击"关于我们"
↓
浏览器向服务器请求 about.html
↓
服务器返回 about.html(整个页面)
↓
浏览器完全刷新,显示新页面
↓
白屏一下,重新加载所有内容
文件结构:
├── index.html ← 首页
├── about.html ← 关于页面
├── contact.html ← 联系页面
├── products.html ← 产品页面
└── ... ← 每个页面一个文件
【单页应用】(SPA = Single Page Application)
用户点击"关于我们"
↓
浏览器不刷新!
↓
JavaScript 把页面内容换掉
↓
地址栏从 / 变成 /about
↓
看起来像换了页面,其实还是同一个页面
文件结构:
├── index.html ← 只有这一个 HTML!
├── app.js ← 所有页面逻辑都在这里
└── style.css
生活比喻
【传统网站】像翻书:
┌─────────────────────────────────────────────────────────┐
│ 想看第 5 章? │
│ ↓ │
│ 翻到第 5 章(请求新页面) │
│ ↓ │
│ 看到全新的一页(页面完全刷新) │
└─────────────────────────────────────────────────────────┘
【单页应用】像看魔术表演:
┌─────────────────────────────────────────────────────────┐
│ 想看第 5 章? │
│ ↓ │
│ 魔术师挥挥手(JavaScript 执行) │
│ ↓ │
│ 书上的字变了,但书还是那本书(页面不刷新) │
└─────────────────────────────────────────────────────────┘
为什么你的 Vue 项目是单页应用?
你用 npm run build 打包后,dist 文件夹里只有:
dist/
├── index.html ← 唯一的 HTML 文件!
├── assets/
│ ├── index-xxx.js ← 所有 Vue 组件编译后的代码
│ └── index-xxx.css ← 所有样式
└── ...
不管用户访问:
- http://你的网站/ → 显示首页(index.html)
- http://你的网站/login → 还是 index.html,Vue Router 显示登录页
- http://你的网站/about → 还是 index.html,Vue Router 显示关于页
- http://你的网站/user/123 → 还是 index.html,Vue Router 显示用户页
所有"页面"都是由 JavaScript 动态渲染出来的!
为什么需要 try_files 配置?
问题:
用户直接访问 http://你的网站/login
↓
Nginx 收到请求:"/login"
↓
Nginx 去找 /usr/share/nginx/html/login 文件
↓
找不到!(因为根本没有这个文件)
↓
返回 404 错误
↓
用户看到"页面不存在" 😢
解决方案(try_files):
用户直接访问 http://你的网站/login
↓
Nginx 收到请求:"/login"
↓
try_files $uri $uri/ /index.html
↓
① 先找 /login 文件 → 没有
② 再找 /login/ 目录 → 没有
③ 返回 /index.html ← 兜底!
↓
浏览器收到 index.html
↓
Vue 和 Vue Router 加载
↓
Vue Router 看到地址是 /login
↓
渲染登录页面组件 😊
一句话总结:单页应用只有一个 HTML,所有"页面"都是 JS 渲染的,所以服务器要配置"找不到就返回 index.html"。
概念三:反向代理
先理解"代理"
【正向代理】你的代理人
场景:你想买国外的东西,但你出不去
↓
找个代购(代理)
↓
代购帮你去国外买
↓
代购把东西给你
技术场景:科学上网
你 → VPN(代理)→ 谷歌
↑
代理帮你访问你访问不了的网站
【反向代理】服务器的代理人
场景:客人来餐厅吃饭
↓
前台接待(Nginx)接待客人
↓
前台把点的菜告诉后厨(后端服务器)
↓
后厨做好菜,给前台
↓
前台把菜端给客人
客人不知道后厨在哪、有几个厨师
客人只跟前台打交道
图解
【没有反向代理】
用户浏览器 ──────────────────────→ 后端服务器(:3000)
│
暴露在外面,不安全
【有反向代理】
┌──→ 后端服务器1(:3000)
│
用户浏览器 ───→ Nginx(:80)──┼──→ 后端服务器2(:3001)
│
└──→ 后端服务器3(:3002)
↑ ↑
用户只能看到 Nginx 后端服务器藏在后面,更安全
为什么需要反向代理?
好处1:隐藏后端
┌─────────────────────────────────────────────────────────┐
│ 用户只知道 www.example.com │
│ 不知道后端服务器在哪个 IP、什么端口 │
│ 更安全 │
└─────────────────────────────────────────────────────────┘
好处2:统一入口
┌─────────────────────────────────────────────────────────┐
│ 前端:www.example.com │
│ API:www.example.com/api/ │
│ 图片:www.example.com/images/ │
│ │
│ 看起来是一个网站,实际上背后可能是多个服务器 │
└─────────────────────────────────────────────────────────┘
好处3:SSL 终端
┌─────────────────────────────────────────────────────────┐
│ 用户 ←──HTTPS──→ Nginx ←──HTTP──→ 后端 │
│ │
│ 只需要在 Nginx 配置 HTTPS │
│ 后端不用管证书的事 │
└─────────────────────────────────────────────────────────┘
配置示例
nginx
server {
listen 80;
server_name www.example.com;
# 静态文件
location / {
root /var/www/html;
index index.html;
}
# API 请求转发给后端
location /api/ {
proxy_pass http://127.0.0.1:3000/;
# ↑
# 把 /api/xxx 请求转发给本机 3000 端口的服务
}
}
用户请求:http://www.example.com/api/users
↓
Nginx 匹配到 location /api/
↓
转发给 http://127.0.0.1:3000/users
↓
后端返回数据给 Nginx
↓
Nginx 返回给用户
一句话总结:反向代理就是 Nginx 当"中间人",把用户的请求转发给后端服务器,用户不直接接触后端。
概念四:负载均衡
什么是负载均衡?
场景:双十一,淘宝有几亿人同时访问
一台服务器能扛住吗?
↓
扛不住!会崩!
↓
怎么办?
↓
用很多台服务器一起扛!
↓
怎么分配请求?
↓
负载均衡!
生活比喻
【没有负载均衡】
银行只有 1 个窗口
↓
100 个客人排队
↓
队伍排到门外
↓
客人等得不耐烦,走了
【有负载均衡】
银行开 5 个窗口
↓
大堂经理(Nginx)分配客人
↓
"1号去1窗口,2号去2窗口..."
↓
每个窗口只排 20 人
↓
很快就办完了
图解
┌──→ 服务器1(处理 33%)
│
用户请求 ───→ Nginx(负载均衡)──┼──→ 服务器2(处理 33%)
│
└──→ 服务器3(处理 33%)
分配策略
【轮询】默认方式
请求1 → 服务器1
请求2 → 服务器2
请求3 → 服务器3
请求4 → 服务器1(又回来了)
...
像发牌一样,一人一张
【权重】按能力分配
服务器1(性能强)weight=3,处理 60%
服务器2(性能弱)weight=2,处理 40%
能力强的多干点活
【IP 哈希】同一用户固定服务器
用户A(IP: 1.1.1.1)→ 永远去服务器1
用户B(IP: 2.2.2.2)→ 永远去服务器2
保证用户的购物车、登录状态不丢失
配置示例:
# 定义后端服务器组
upstream backend_servers {
# 负载均衡策略:
# 默认:轮询(round-robin)
# ip_hash:根据 IP 分配(会话保持)
# least_conn:最少连接
# weight:权重
ip_hash; # 使用 IP 哈希
server 192.168.1.101:8080 weight=3; # 权重 3
server 192.168.1.102:8080 weight=2; # 权重 2
server 192.168.1.103:8080 weight=1; # 权重 1
server 192.168.1.104:8080 backup; # 备用服务器
}
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://backend_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
一句话总结:负载均衡就是把很多请求分散到多台服务器,避免一台服务器被压垮。
概念五:HTTPS
HTTP vs HTTPS
【HTTP】明文传输
┌─────────────────────────────────────────────────────────┐
│ │
│ 你 ──────"密码是123456"─────→ 网站 │
│ ↑ │
│ 黑客可以偷听到! │
│ 就像在公共场合大声说话 │
│ │
└─────────────────────────────────────────────────────────┘
【HTTPS】加密传输
┌─────────────────────────────────────────────────────────┐
│ │
│ 你 ──────"@#$%^&*加密内容"─────→ 网站 │
│ ↑ │
│ 黑客听到也看不懂! │
│ 就像用密码本传递信息 │
│ │
└─────────────────────────────────────────────────────────┘
生活比喻
HTTP = 明信片
┌─────────────────────────────────────────────────────────┐
│ 邮递员、路人都能看到你写的内容 │
└─────────────────────────────────────────────────────────┘
HTTPS = 带锁的保险箱
┌─────────────────────────────────────────────────────────┐
│ 只有收件人有钥匙,别人打不开 │
└─────────────────────────────────────────────────────────┘
HTTPS 工作原理(简化版)
1. 你访问 https://银行.com
2. 网站出示"身份证"(SSL证书)
证书上写着:"我确实是银行.com,不是假冒的"
证书由权威机构(CA)签发
3. 浏览器验证证书
"证书是真的,你确实是银行.com"
4. 双方协商一个"密码本"(加密密钥)
5. 之后所有通信都用这个"密码本"加密
黑客即使截获也看不懂
为什么需要 HTTPS?
✓ 数据加密 - 密码、银行卡号不会被偷
✓ 身份验证 - 确保你访问的是真网站,不是钓鱼网站
✓ 数据完整 - 确保数据没被篡改
现代浏览器对 HTTP 网站会显示"不安全"警告
搜索引擎优先收录 HTTPS 网站
示例
server {
listen 443 ssl http2;
server_name www.example.com;
# SSL 证书配置
ssl_certificate /etc/nginx/ssl/example.com.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
# SSL 安全配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# HSTS(强制 HTTPS)
add_header Strict-Transport-Security "max-age=31536000" always;
root /var/www/example;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
# HTTP 跳转 HTTPS
server {
listen 80;
server_name www.example.com example.com;
return 301 https://www.example.com$request_uri;
}
一句话总结:HTTPS 就是给 HTTP 加了一把锁,让数据传输更安全。
概念六:跨域(CORS)
什么是跨域?
【同源】
你的网页:https://www.example.com
请求地址:https://www.example.com/api/users
↓
协议相同(https)、域名相同(www.example.com)、端口相同
↓
这是"同源",浏览器允许
【跨域】
你的网页:https://www.example.com
请求地址:https://api.other.com/users
↓
域名不同!
↓
这是"跨域",浏览器默认禁止!
为什么浏览器要禁止跨域?
安全考虑!
假设没有跨域限制:
1. 你登录了银行网站,有登录状态(Cookie)
2. 你不小心打开了一个恶意网站
3. 恶意网站的 JS 代码偷偷请求:
fetch('https://银行.com/api/转账?to=黑客&amount=100万')
4. 因为你有银行的 Cookie,请求会带上你的身份
5. 钱就被转走了!
有了跨域限制:
恶意网站的 JS 无法请求其他网站的 API
你的银行账户就安全了
生活比喻
跨域限制 = 小区门禁
你是 A 小区的住户(www.a.com)
↓
你可以自由进出 A 小区(请求 www.a.com)
↓
但你不能随便进 B 小区(请求 www.b.com)
↓
除非 B 小区物业说"让他进来"(服务器允许跨域)
怎么解决跨域?
方法:服务器告诉浏览器"我允许他访问"
服务器返回响应头:
Access-Control-Allow-Origin: https://www.example.com
意思是:
"我允许 https://www.example.com 这个网站的 JS 访问我"
浏览器看到这个头,就放行了
你的项目为什么没有跨域问题?
开发时:
┌─────────────────────────────────────────────────────────┐
│ 你的前端:http://localhost:5173 │
│ 后端 API:http://localhost:8080 │
│ │
│ 端口不同,本来会跨域 │
│ │
│ 但是 Vite 开发服务器配置了代理: │
│ /api/* → 转发到 localhost:8080 │
│ │
│ 所以前端请求 /api/xxx │
│ 实际上是请求 localhost:5173/api/xxx │
│ Vite 再转发给 localhost:8080 │
│ │
│ 浏览器看到的是同源请求,不会跨域! │
└─────────────────────────────────────────────────────────┘
生产时(用 Nginx):
┌─────────────────────────────────────────────────────────┐
│ 前端和 API 都走 www.example.com │
│ │
│ 前端:www.example.com/ │
│ API:www.example.com/api/ │
│ │
│ Nginx 把 /api/ 转发给后端 │
│ 用户浏览器看到的都是同一个域名 │
│ 没有跨域问题! │
└─────────────────────────────────────────────────────────┘
一句话总结:跨域是浏览器的安全限制,阻止网页 JS 请求其他网站;通过服务器配置或代理可以解决。
概念七:限流
什么是限流?
场景:
你开了一家小餐厅,最多同时接待 50 人
↓
突然来了 500 人
↓
厨房爆炸,服务员崩溃,谁都吃不上饭
↓
餐厅倒闭
解决方案:
在门口放个保安(限流)
↓
"店里已经 50 人了,请排队等候"
↓
控制进入的人数
↓
餐厅正常运营
限流的作用
1. 保护服务器不被压垮
2. 防止恶意攻击
- 有人写脚本疯狂请求你的网站
- 1秒钟请求1万次
- 想把你的服务器搞崩
- 限流:每秒最多10次,超过的拒绝
3. 公平分配资源
- 不让一个用户占用所有资源
- 大家都能用
限流策略
【按请求频率限制】
每秒最多处理 100 个请求
第 101 个请求:等一下或者返回错误
【按 IP 限制】
每个 IP 每秒最多 10 个请求
防止单个用户/攻击者发太多请求
【按用户限制】
每个登录用户每分钟最多 100 个请求
API 接口常用这种
【按并发连接限制】
同时最多 1000 个连接
超过的等着
一句话总结:限流就是控制请求数量,防止服务器被压垮或被攻击。
总结:一张图理解所有概念
互联网
│
▼
┌──────────────────┐
│ │
│ 用户的浏览器 │
│ │
└────────┬─────────┘
│
│ HTTPS(加密传输)
│
▼
┌────────────────────────────────────────────────────────────────┐
│ │
│ Nginx(门卫 + 前台) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 限流 │ │ 跨域处理 │ │ 负载均衡 │ │
│ │ 控制流量 │ │ 允许/拒绝 │ │ 分发请求 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ │ │ │ │
│ │ 静态托管 │ │ 反向代理 │ │
│ │ 返回 HTML/CSS/JS/图片 │ │ 转发 API 请求给后端 │ │
│ │ │ │ │ │
│ └─────────────────────────┘ └───────────┬─────────────┘ │
│ │ │ │
└───────────┼───────────────────────────────┼───────────────────┘
│ │
▼ ▼
┌───────────────┐ ┌───────────────────────┐
│ │ │ │
│ dist 文件夹 │ │ 后端服务器集群 │
│ (Vue 打包) │ │ ┌─────┐ ┌─────┐ │
│ │ │ │ 1 │ │ 2 │ ... │
│ index.html │ │ └─────┘ └─────┘ │
│ app.js │ │ │
│ style.css │ │ 处理 API 请求 │
│ │ │ 查询数据库 │
└───────────────┘ └───────────────────────┘
│
│
▼
┌───────────────┐
│ │
│ 单页应用 │
│ (SPA) │
│ │
│ Vue Router │
│ 处理前端路由 │
│ │
└───────────────┘
对应你项目的情况
| 概念 | 你的项目怎么用的 |
|---|---|
| 静态托管 | Nginx 托管 dist 文件夹里的 Vue 打包文件 |
| 单页应用 | Vue + Vue Router,只有一个 index.html |
| 反向代理 | 开发时 Vite 代理 /api,生产时 Nginx 代理 |
| 负载均衡 | 目前没用到(单服务器),以后可以扩展 |
| HTTPS | 目前配置文件没有,生产环境需要添加 |
| 跨域 | 通过代理解决,不需要额外配置 |
| 限流 | 目前没用到,可以根据需要添加 |
现在这些概念应该清楚多了吧?有任何还不理解的地方,随时问我!