返回首页

关于Nginx

布莱克2026-04-16 16:46已编辑
Tip:文章封面与内容无关,作者旅游时拍摄,因为没什么值得把四季都错过!

Nginx 是一个 高性能的 HTTP 和反向代理 Web 服务器

反向代理(Reverse Proxy)

这是博主目前正在使用的功能,也是 Nginx 最伟大的发明之一。

它解决了什么?

  • 跨域隔离:浏览器因为“同源策略”限制不同域名的通信,但 Nginx 站在前端域名的背后,悄悄把请求转发给后端,欺骗浏览器认为这是同源请求。
  • 隐藏后端架构:用户永远不知道你的 后端 跑在哪个端口,甚至不知道你后端是用 Node.js、Java 还是 Python 写的。这增加了系统的安全性。
  • 协议转换:你可以在 Nginx 这一层统一处理 HTTPS,而内网转发给 后端 时使用 HTTP,减轻后端代码的复杂度


静态资源托管与缓存

这是前端最应该关心的功能。

它解决了什么?

  • 性能瓶颈:Node.js 处理逻辑很强,但在“搬运文件”上远不如 Nginx。Nginx 使用了 sendfile 技术,直接在内核空间完成文件传输,速度比 Node.js 快数倍。
  • 浏览器缓存控制:你可以非常方便地通过 Nginx 给 assets 里的 JS/CSS 设置 Cache-Control 或 Expires。
  • Gzip/Brotli 压缩:Nginx 可以在传输前实时压缩文件,让你的首屏加载速度从 3s 变成 1s。


负载均衡

当你的 博客 从每天 100 个人看变成 100 万人看时,单台 进程一定会崩溃。

它解决了什么?

高可用性:你可以启动 5 个 Express 进程,Nginx 会像发牌员一样,把流量均匀分配给它们。如果其中一个挂了,Nginx 会自动把请求分给剩下的。

水平扩展:当你需要扩容时,只需在 Nginx 配置文件里加一行 IP 地址


比如通过 PM2 启动了多个项目,其实已经在单机层面接触到了“并行”的概念。而 Nginx 的 upstream 模块,则是将这种并行从“单机”推向“集群”的关键。

场景模拟:

假设你现在有一台服务器 A(IP: 1.1.1.1),上面跑着你的 blog。随着流量增加,CPU 经常 100%,你又买了两台服务器 B(2.2.2.2)和 C(3.3.3.3),上面也部署了一模一样的代码。

在 Nginx 配置中定义一个 upstream 块,把这三台服务器的地址写进去。

# 1. 定义服务器池
upstream blog_cluster {
    # 轮询(默认):每个请求按时间顺序逐一分配到不同的后端服务器
    server 1.1.1.1:4000;
    server 2.2.2.2:4000;
    server 3.3.3.3:4000;
    
    # 备用机:只有当上面三台都挂了,才会把请求发给这台
    server 4.4.4.4:4000 backup;
}

server {
    listen 80;
    server_name blackztt.cn;

    location / {
        # 2. 将流量转发给上面定义的服务器池,而不是具体的 IP
        proxy_pass http://blog_cluster;
        
        proxy_set_header Host $host;
        # ... 其他 header
    }
}

服务器池的定义:

情况 A:单机多项目

  • 定义位置:定义在当前这一台服务器的 Nginx 配置里。
  • 原理:你的 Nginx 收到请求,发现需要转发给 blog_cluster,它就在自己的配置文件里找,然后转发给本地的端口(比如 4000, 4001)。

情况 B:多机集群

  • 定义位置:定义在“入口 Nginx”(即负载均衡器)上。
  • 架构逻辑:你有一台专门的 入口服务器,它不跑业务,只跑 Nginx。在这个入口 Nginx 的配置里,定义 upstream,里面写上服务器 B、C、D 的私网 IP。所有的 upstream 定义只存在于这台入口机上。


负载均衡策略

决定了当一个请求进来时,到底该发给后端“服务器池”里的哪一个实例

轮询 (Round Robin) —— 默认策略

这是 Nginx 默认的算法。请求像报数一样,按顺序分配:第一个请求给 A,第二个给 B,第三个给 C,循环往复。

  • 特点:绝对公平。
  • 适用场景:后端服务器硬件配置完全相同,且业务逻辑是“无状态”的。
  • 缺点:不考虑服务器压力。如果 A 正在处理一个超大文件(很累),B 很闲,轮询依然会把新请求给 A。


加权轮询

如果你有两台服务器,一台是 8 核 16G,另一台是 2 核 4G,显然 8 核的应该多干活。

  • 配置示例:Nginxupstream backend { server 127.0.0.1:4000 weight=3; # 接收 75% 的流量 server 127.0.0.1:4001 weight=1; # 接收 25% 的流量 }
  • 适用场景:后端服务器性能不均衡。


最少连接

这是一种更“智能”的动态算法。Nginx 会记录每一台后端服务器当前正在处理多少个连接,新请求会发给那个连接数最少的服务器。

  • 配置示例:least_conn;
  • 适用场景:请求处理时间长短不一。比如有的接口 10ms 完事,有的接口要跑 5s 的报表。最少连接能有效防止某台服务器被“长连接”压跨。


Nginx配置

Location 匹配的“权杖”顺序

location = /path:精确匹配。优先级最高,匹配到就直接停止。

location ^~ /static/:前缀匹配。如果匹配到,就不再查后面的正则表达式。

location ~ \.php$:正则匹配。区分大小写(~* 不区分)。按配置文件的先后顺序,谁在前面谁赢。

location /:通用匹配。优先级最低,作为兜底。


当配置反向代理时,这几行是必须

proxy_set_header Host $host;                      # 告诉后端,用户访问的是哪个域名
proxy_set_header X-Real-IP $remote_addr;          # 告诉后端,用户的真实 IP 是什么
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 代理链路追踪
proxy_set_header X-Forwarded-Proto $scheme;       # 告诉后端是 http 还是 https


开启gzip压缩(经验证开启压缩后比之前Performance提高了近20分)

# 1. 开启 Gzip
    gzip on;

    # 2. 只有超过这个大小的文件才压缩(太小的文件压了反而可能变大)
    gzip_min_length 1k;

    # 3. 压缩级别:1-9。
    # 建议设为 5 或 6。级别越高压缩越小,但越费服务器 CPU。5 是性价比最高点。
    gzip_comp_level 5;

    # 4. 针对哪些类型的文件进行压缩(必须要包含 JS 和 CSS)
    gzip_types text/plain application/javascript text/css application/json application/xml text/javascript;


前端静态资源配置

location / {
    # Vite 项目在服务器上的实际存放路径
    root /var/blog-admin;
    index index.html index.htm;

    # 核心配置:解决 Vue3/Vite 项目刷新页面出现 404 的问题
    # 尝试寻找文件,找不到则重定向到 index.html 让前端路由接管
    try_files $uri $uri/ /index.html;
}


try_files $uri $uri/ /index.html; —— 关键

这是为了解决 Vue-Router / React-Router 在 History 模式下刷新 404 的神级配置。

为什么需要它?(痛点分析)

  1. 前端路由是“假”的:在 Vue 项目中,你访问 /user/profile,这只是浏览器地址栏里的一个字符串。
  2. 后端寻址是“真”的:如果你刷新页面,浏览器会向 Nginx 请求 /user/profile 这个物理路径。
  3. 矛盾点:你的服务器磁盘上根本没有一个叫 /user/profile/ 的文件夹,也没有对应的 index.html。如果不配这一行,Nginx 找不到文件,就会直接报 404 Not Found。

try_files 的执行逻辑(三步走):

  • 第一步 $uri:Nginx 先看磁盘上有没有这个文件。如果是 main.css 这种真实存在的文件,直接返回。
  • 第二步 $uri/:如果没有文件,再看磁盘上有没有这个目录。
  • 第三步 /index.html:(这是绝招) 如果前两步都失败了,Nginx 不会报错,而是把请求“强行”转发给 /index.html
assistant