加载中...

直连 Next.js(:3000)能正常显示新内容,但经过 Nginx 反向代理(:80)的站点却显示老页面的排查和解决

Nginx 默认缓存了 Next.js 返回的 HTML 页面,导致代码更新后新内容不生效。
实战项目 · 0 课时
← 上一节 下一节 → 返回详情

在一个next.js的前端项目中遇到了奇怪的问题:

直连 Next.js:3000)能正常显示新内容,但经过 Nginx 反向代理:80)的站点却显示老页面。

  • :3000直连 Next.js 容器,不经过 Nginx
  • :80(不带端口)才是经过 Nginx 反向代理的入口

结论:

直接访问 :3000 端口能看到最新代码,但通过域名(走 Nginx 反代)访问却看到旧页面——因为 Nginx 把旧页面缓存了 1 年没刷新。

 

一、问题现象

| 访问方式 | 表现 |
|---------|------|
| `http://www.cnzhanzhang.com:3000` | 导航栏正常,显示"HOMExxx"(最新代码) |
| `http://www.cnzhanzhang.com`(80端口) | 导航栏不显示最新内容,显示旧版页面 |

### 二、排查过程

**第一层:排除环境变量问题**
- 网上建议加 `NEXT_PUBLIC_BASE_URL` 和 `NEXT_PUBLIC_APP_URL`
- 检查代码:整个项目**零引用**这两个变量 → ❌ 无效

**第二层:排除 Nginx `^~` 问题**
- 网上建议把 `location ^~ /` 改成 `location /`
- 检查实际配置:本来就是 `location /`,没有 `^~` → ❌ 无效

**第三层:检查 Nginx 配置**
- 确认 Nginx 是宝塔面板安装,配置路径 `/www/server/panel/vhost/nginx/`
- 配置本身正确,`proxy_pass http://127.0.0.1:3000` 指向正确

**第四层:检查 Docker 容器**
- 发现 `opc-website` 容器**没有挂载目录**,代码烘焙在镜像里
- 服务器源码目录 `/www/wwwroot/www.cnzhanzhang.com/` 里是旧代码(HOMExxx)
- 但容器里跑的镜像是新的 → 说明之前构建过但没重新 build

**第五层:检查缓存**
- 发现响应头:`Cache-Control: s-maxage=31536000`(缓存1年)
- `x-nextjs-cache: HIT` → Next.js 返回了缓存的旧页面

**第六层:最终定位**
- 把 `proxy_pass` 从 `127.0.0.1:3000` 改成 `www.cnzhanzhang.com:3000` 后正常
- 说明 **Nginx 的 proxy_cache 缓存了旧响应**

### 三、根因

**Next.js SSG 默认缓存 1 年** + **Nginx 默认开启 proxy_cache** = 旧页面被缓存,新代码更新后不生效。

### 四、解决方案

在 Nginx 配置里加两行:

```nginx
proxy_cache off;
add_header X-Proxy-Cache "BYPASS";
```

完整配置:

```nginx
server {
    listen 80;
    server_name cnzhanzhang.com www.cnzhanzhang.com;
    client_max_body_size 50M;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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_cache_bypass $http_upgrade;
        proxy_no_cache 1;
        proxy_buffering off;
        proxy_cache off;
        add_header X-Proxy-Cache "BYPASS";
    }
}
```

### 五、经验教训

  1. **不要盲从网上建议** — 先确认代码里是否真的引用了那些变量/配置
    2. **Docker 容器代码是烘焙在镜像里的** — 改源码必须重新 `docker compose build`
    3. **Next.js 静态页面默认缓存 1 年** — 开发环境需在 `next.config.ts` 里覆盖 `headers()`
    4. **Nginx proxy_cache 默认行为** — 会缓存后端响应,开发环境建议关闭
    5. **排查问题要逐层深入** — 环境变量 → Nginx → Docker → 缓存,每层验证后再进入下一层