Next.js 线上白屏问题排查指南(pm2部署版)

2025/7/1 Next.jspm2Error白屏

线上用户反馈页面白屏是一个**P0级(最高优先级)**的紧急问题。现在我们的 Next.js 应用是使用 PM2 直接部署在服务器(可能是虚拟机或物理机)上的。排查逻辑——区分客户端与服务端、以日志为中心

🌙 PM2 环境下的应急响应与定位流程

🌙 第 1 阶段:紧急评估与快速止损 (First 5 Minutes)

1. 复现与浏览器端分析 (与之前一致)

  • 隐身模式打开出问题的页面。
  • 打开开发者工具 (F12)
    • Console (控制台): 是否有 JavaScript 错误?这是区分客户端/服务端问题的第一个关键线索。
    • Network (网络): 页面本身(HTML 文档)的请求状态码是 200 还是 5xx?

2. 立刻检查 PM2 日志! 这是整个排查过程的核心。你需要 SSH 登录到应用服务器。PM2 会管理应用的日志输出 (stdout) 和错误输出 (stderr)。

# 1. 查看由 PM2 管理的所有应用的状态
pm2 status

# 2. 查看应用的实时日志 (将 <app_name> 替换为你的应用名或ID)
# 这是最常用的命令,会同时显示标准输出和错误输出
pm2 logs <app_name>

# 3. 只看错误日志,这通常更有价值!
pm2 logs <app_name> --err

# 4. 如果日志太多,可以只看最后几百行
pm2 logs <app_name> --lines 200
1
2
3
4
5
6
7
8
9
10
11
12

在日志中你要寻找什么?

  • 任何 Error: 开头的堆栈跟踪 (stack trace)。
  • 数据库连接错误、第三方 API 超时、文件权限问题等。
  • 特别注意,如果应用频繁重启,pm2 status 会显示 restarts 次数很高。这通常是致命错误导致进程崩溃的迹象。

3. 快速决策:回滚 如果问题是最近的上线导致的,最快的恢复方法是回滚代码。在 PM2 的场景下,通常是一个原子化的操作:

  • 常见的部署策略(如 Capistrano 风格)会将每个版本部署到带时间戳的目录中,并用一个名为 current 的软链接指向当前版本。
  • 回滚操作:将 current 软链接指向上一个稳定的版本目录,然后执行 pm2 reload <app_name>。这可以实现零停机回滚。

🌙 第 2 阶段:深度定位问题根源

🌙 场景一:定位客户端错误 (浏览器控制台有 JS 错)

挑战:和 Docker 场景一样,你看到的将是压缩后的代码堆栈。

解决方案:本地复现与 Source Map 解码

  1. 获取构建产物: 你的构建产物(包括 Source Maps)就在服务器的文件系统上,位于你的项目部署目录下的 .next 文件夹里。你可以使用 scprsync 将整个 .next 目录从服务器下载到本地。

    # 语法: scp -r user@your_server_ip:/path/to/your/app/.next ./
    scp -r ubuntu@123.45.67.89:/var/www/my-app/current/.next ./local-next-build
    
    1
    2
  2. 手动解码: 有了 .next 目录,接下来的步骤就和 Docker 场景完全一样了:找到报错的文件名、行列号,然后使用 source-map 库或在线工具,结合对应的 .map 文件来定位到原始的 TypeScript 代码。

🌙 场景二:定位服务端错误 (页面请求 500 或 PM2 不断重启)

这是 PM2 环境下最需要关注的情况。

解决方案:深挖日志、检查环境和系统资源

  1. 深挖 PM2 日志

    • pm2 logs --err 是你的好朋友。服务端的堆栈跟踪是可读的,会直接指向你代码中的文件和行号。
    • 实施结构化日志:这个建议依然适用。将错误包装在 JSON 对象中输出,可以让日志分析事半功倍。
  2. 检查环境变量: PM2 应用的环境变量来源主要有两个:

    • ecosystem.config.js 文件:这是 PM2 的最佳实践。检查项目根目录下的这个文件,特别是 envenv_production 部分。
      // ecosystem.config.js
      module.exports = {
        apps: [{
          name: 'my-next-app',
          script: 'node_modules/.bin/next',
          args: 'start',
          env_production: {
            NODE_ENV: 'production',
            PORT: 3000,
            // 检查这里的 DATABASE_URL, API_KEY 等是否正确配置
            DATABASE_URL: '...', 
          }
        }]
      };
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
    • 系统级环境变量:检查运行 PM2 的用户的环境变量设置,如 ~/.bashrc~/.profile。使用 echo $VARIABLE_NAME 确认。
  3. 检查系统资源 (PM2 独特优势与劣势) 与 Docker 不同,PM2 进程与服务器上的其他进程共享资源。资源耗尽是常见问题。

    • 内存溢出 (Out of Memory): Node.js 应用如果内存泄漏,可能会被系统的 OOM Killer 杀死,导致 PM2 不断重启。
      • 使用 pm2 monit:这个命令提供了一个漂亮的终端仪表盘,可以实时监控每个应用的 CPU 和内存使用情况。
      • 使用系统命令htoptop 可以看到进程的资源占用。dmesg -T | grep -i "killed process" 可以查看是否有进程被系统杀死。
    • CPU 占用过高: 检查是否有死循环或高计算量的操作。
  4. 检查文件权限

    • 确认运行 PM2 的用户(在 pm2 status 中可以看到 user)对项目目录有正确的读/写权限,特别是对 .next 目录和任何需要写入的缓存目录。
    • 使用 ls -l /path/to/your/app 来检查。

🌙 PM2 环境下的白屏问题排查清单

  1. [ ] 复现: 在浏览器隐身模式下复现问题,检查控制台网络面板,初步判断是客户端还是服务端问题。
  2. [ ] 查日志: ssh 登录服务器,立即执行 pm2 logs <app_name> --err --lines 200 查看错误日志。
  3. [ ] 查状态: pm2 status,检查应用的 status 是否为 onlinerestarts 次数是否异常高。
  4. [ ] 决策: 如果是新上线导致,通过修改软链接并 pm2 reload <app_name> 立即回滚
  5. [ ] 深度定位:
    • 客户端问题: scp 下载 .next 目录,在本地进行 Source Map 解码。
    • 服务端问题:
      • [ ] 仔细分析 pm2 logs 中的堆栈跟踪。
      • [ ] 检查 ecosystem.config.js 中的环境变量是否正确。
      • [ ] 使用 pm2 monithtop 检查应用的内存和 CPU 使用情况,排查资源耗尽问题。
      • [ ] 使用 ls -l 检查文件权限是否正确。
  6. [ ] 修复与预防:
    • [ ] 修复代码后,通过 CI/CD 流程或手动部署新版本。
    • [ ] 强烈建议: 推动运维或自己动手,将 PM2 的日志(位于 ~/.pm2/logs/)通过 Filebeat 等工具转发到集中的日志平台(如 ELK, Loki)。
    • [ ] 强烈建议: 为你的应用创建一个 /api/health 健康检查接口,并使用外部监控工具(如 Uptime Kuma 或一个简单的 cron 脚本)定期调用,实现应用存活监控。

🌙 总结

线上白屏问题在 PM2 环境下的排查流程与 Docker 有很多相似之处,但也有其独特的挑战和解决方案。通过系统化的日志分析、环境检查和资源监控,你可以快速定位问题并恢复服务。同时,建立良好的日志和健康检查机制,将大大提高未来问题的排查效率。

Next.js 线上白屏问题排查指南(Sentry监控版)

Next.js 线上白屏问题排查指南(Docker部署版)