使用 curl 排查 Nginx、PM2 与 Express 请求问题

本章面向第一次在 Ubuntu 上排查 Node.js 接口问题的开发者。我们从一个常见现象出发,学习如何用几条命令逐层缩小问题范围:

curl http://127.0.0.1:8080/api/user

能够正常返回,但是:

curl https://www.example.com/api/user

却返回 404 Not Found

学完本章后,你应该能够判断:Express 是否正常、PM2 是否正常管理进程、请求是否到达 Nginx,以及 404、502 更可能来自哪一层。

域名、端口和 PM2 应用名都是示例,请替换为服务器的真实值。

1. 先理解请求链路

通过域名访问接口时,请求通常经过:

curl 或浏览器
      ↓
DNS:把域名解析成服务器 IP
      ↓
Nginx:监听 80/443,选择 server 和 location
      ↓
Express:监听 127.0.0.1:8080,处理 API 路由
      ↑
PM2:启动和管理 Node.js 进程

PM2 不处理 HTTP 请求。它负责在后台启动 Node.js、查看进程和日志、在进程异常退出后重启。真正处理 HTTP 请求的是 Nginx 和 Express。

下面两条命令走的链路不同:

curl http://127.0.0.1:8080/api/user
curl → Express

而:

curl https://www.example.com/api/user
curl → DNS → Nginx → Express

所以,第一条命令正常只能证明 Express 能处理这个请求,不能证明域名、HTTPS 和 Nginx 都正常。

2. 从最基础的 curl 开始

curl 是一个命令行网络客户端。在没有浏览器的 Ubuntu 服务器上,可以用它发送 HTTP 请求:

curl https://www.example.com/api/user

默认情况下,curl 主要把响应体打印到终端:

{"code":0,"data":{"id":1,"name":"Alice"}}

只看响应体不足以排错,还需要查看状态码、响应头、连接 IP 和 HTTPS 握手过程。

3. curl -i:查看响应头

curl -i https://www.example.com/api/user

-i--include 的缩写,表示把响应头也包含在输出中:

HTTP/1.1 404 Not Found
Server: nginx
Content-Type: text/html
Content-Length: 153

<html><body>404 Not Found</body></html>

这里可以看到:

不要把 -i 和大写的 -I 混淆:

curl -I https://www.example.com/api/user

-I 会发送 HEAD 请求。接口可能只实现了 GET,所以排查普通 GET 接口时优先使用 -i

4. curl -v:查看完整通信过程

curl -v https://www.example.com/api/user

-v--verbose 的缩写,表示输出详细过程,包括:

详细输出中有三个重要前缀:

*  curl 自身的连接、DNS 和 TLS 诊断信息
>  curl 发给服务器的请求
<  服务器返回给 curl 的响应

例如:

* Host www.example.com:443 was resolved.
* IPv4: 203.0.113.10
* Trying 203.0.113.10:443...
* Connected to www.example.com (203.0.113.10) port 443
> GET /api/user HTTP/1.1
> Host: www.example.com
> User-Agent: curl/8.5.0
< HTTP/1.1 404 Not Found
< Server: nginx

初学阶段先关注四项:

  1. Trying 后面的 IP 是否为预期服务器;
  2. > 后面的请求方法和路径是否正确;
  3. Host 是否为预期域名;
  4. < HTTP/... 后面的状态码是什么。

-v 的诊断通常写入标准错误流,响应体写入标准输出流。因此重定向响应体后,终端上仍可能看到诊断信息,这是正常现象。

5. curl -k:临时跳过证书校验

curl -k https://www.example.com/api/user

-k--insecure 的缩写。它让 curl 暂时跳过 HTTPS 服务器证书的身份校验,例如自签名证书、域名不匹配或证书链不完整。

-k 不会:

HTTPS 通信仍然加密,但 curl 不再可靠确认对方身份。因此 -k 只适合诊断,不应该成为生产调用的长期方案。

可以对比:

curl -v https://www.example.com/api/user
curl -vk https://www.example.com/api/user

如果不加 -k 失败、加上后成功,应该修复证书,而不是永久忽略校验。

6. curl -vk 到底表示什么

短参数可以合并:

curl -v -k https://www.example.com/api/user

等价于:

curl -vk https://www.example.com/api/user

其中:

-v:显示 DNS、连接、TLS、请求和响应的详细过程
-k:本次请求暂时忽略 HTTPS 证书校验错误

-vk 适合第一次观察 HTTPS 请求发生了什么,但不要因为它方便就忽略其中暴露的证书问题。

7. 第一步:绕过 Nginx,直接检查 Express

在 Ubuntu 服务器内部执行:

curl -i http://127.0.0.1:8080/api/user

返回 200

说明 8080 可以连接、Express 正在运行、该 GET 路由存在。问题更可能在 Nginx、域名或 HTTPS 层。

连接被拒绝

curl: (7) Failed to connect to 127.0.0.1 port 8080

优先检查:PM2 中应用是否启动、Express 是否监听 8080、.envPORT 是否改变,以及应用是否反复崩溃。

Express 返回 404

说明请求已经到达 Express,但可能是请求路径、GET/POST 方法、Router 挂载前缀不匹配,或者新代码没有构建和重新加载。

检查端口监听:

sudo ss -lntp | grep ':8080'

看到 127.0.0.1:8080 表示服务只允许本机访问。由同一台机器上的 Nginx 反向代理时,这是合理的选择。

8. 第二步:检查 PM2

查看进程状态

pm2 status
状态 含义
online 进程当前正在运行
stopped 进程已经停止
errored 进程反复启动失败或进入错误状态

online 只表示进程存在,不保证每个接口以及 MySQL、Redis 等依赖都正常。

查看详细信息

pm2 describe nloop

重点检查:

查看最近日志

pm2 logs nloop --lines 50 --nostream

持续观察使用:

pm2 logs nloop

Ctrl+C 只退出日志查看,不会停止应用。

如果配置了请求日志,可以一边观察 PM2 日志,一边发送请求。Nginx 收到请求但应用没有对应记录,通常说明请求没有代理到 Express;如果应用没有请求日志,则不能仅凭“没有日志”下结论。

PM2 按 Linux 用户保存进程,下面两条命令可能看到不同列表:

pm2 status
sudo pm2 status

不要混用 root 和普通用户管理同一个应用。

9. 第三步:检查 Nginx

查看 Nginx 状态

sudo systemctl status nginx

常见状态:

检查配置语法

sudo nginx -t

成功时通常看到:

syntax is ok
test is successful

必须牢记:

nginx -t 只检查磁盘配置语法,不会让运行中的 Nginx 使用新配置。

修改配置后通常执行:

sudo nginx -t && sudo systemctl reload nginx

&& 表示只有配置检查成功,才执行 reload。

reload 与 restart

sudo systemctl reload nginx

reload 会让新 worker 使用新配置,并尽量让旧 worker 完成已有请求。修改配置后优先使用它。

sudo systemctl restart nginx

restart 会停止后重新启动 Nginx,可能产生短暂中断。通常在 Nginx 状态异常、reload 无法解决或确实需要完整重启时使用。

10. 第四步:查看 Nginx 日志

查看最近 50 行访问日志:

sudo tail -n 50 /var/log/nginx/access.log

查看最近 50 行错误日志:

sudo tail -n 50 /var/log/nginx/error.log

持续观察访问日志:

sudo tail -f /var/log/nginx/access.log

在另一个终端发送请求:

curl -vk https://www.example.com/api/user

tail -f 会等待新日志,按 Ctrl+C 退出观察。

现象 初步判断
当前服务器 access log 有记录 请求到达了当前 Nginx
当前服务器没有记录 DNS 可能指向其他服务器,或请求没有到达这里
error log 出现 Connection refused Nginx 无法连接 Express 端口
Nginx 和应用都记录了请求 请求已经到达 Express
Nginx 有记录,应用没有请求记录 可能没有进入代理 location,需要结合配置确认

如果使用了自定义日志路径,应以实际配置为准。可以打印完整的磁盘配置:

sudo nginx -T

-T 会检查并打印所有 include 合并后的配置,输出可能很长。

11. 初学者需要看懂的 Nginx 配置

一个简化的 HTTPS 反向代理配置是:

server {
    listen 443 ssl;
    server_name www.example.com;

    location /api/ {
        proxy_pass http://127.0.0.1:8080;
    }
}
指令 作用
listen 443 ssl 接收 443 端口的 HTTPS 请求
server_name 指定哪些域名使用这个 server 块
location /api/ 匹配以 /api/ 开头的请求
proxy_pass 把请求转发到 Express

如果 server_name 没有匹配 www.example.com,请求可能进入另一个默认站点。

如果 /api/ 的 location 没有加载,请求可能进入静态页面 location。Nginx 找不到 /api/user 对应的文件时,就会返回 404。

12. proxy_pass 末尾斜杠为什么重要

下面两个配置只差一个 /,但转发路径不同。

保留 /api/ 前缀

location /api/ {
    proxy_pass http://127.0.0.1:8080;
}

客户端请求 /api/user,Express 通常仍收到:

/api/user

去掉匹配到的 /api/ 前缀

location /api/ {
    proxy_pass http://127.0.0.1:8080/;
}

客户端请求 /api/user,Express 通常收到:

/user

如果 Express 只定义了 /api/user,第二种配置可能让 Express 返回 404。

最简单的验证方式是对比:

curl -i http://127.0.0.1:8080/api/user
curl -vk https://www.example.com/api/user

再结合 Express 请求日志观察它最终收到的 URL。

13. 如何初步判断 404 来自哪里

现象 更应该先检查
直接访问 8080 也返回 404 Express 路由和请求方法
8080 正常,域名返回 404 Nginx 的 server、location 和 proxy_pass
Nginx 与 Express 都记录了请求 Express 最终收到的路径
Nginx 有记录,Express 没有请求记录 请求可能没有进入 proxy_pass
当前服务器没有 Nginx 访问日志 DNS、IPv6、CDN 或其他服务器

响应中出现:

Server: nginx

只能证明响应经过 Nginx,不能百分之百证明 404 由 Nginx 产生。Express 返回的 404 也可能经 Nginx 转发给客户端。

14. 常见状态码告诉了我们什么

状态码 常见含义 首先检查
404 路径没有匹配 Nginx location、proxy_pass、Express Router
502 Nginx 无法正常连接上游 PM2、Express 端口、proxy_pass 地址
504 Nginx 等待上游超时 慢接口、数据库、Nginx 超时配置
301/302 发生重定向 响应中的 Location

如果 Nginx 已启动但 Express 尚未启动,常见结果是 502 Bad Gateway,而不是 404。Express 后来开始监听后,Nginx 通常会自动恢复连接,不需要为此重启 Nginx。

15. 为什么重启后恢复不等于找到原因

假设:

127.0.0.1:8080/api/user 正常
https://www.example.com/api/user 返回 404

随后执行:

sudo nginx -t && sudo systemctl restart nginx

问题消失。最常见的解释是:

磁盘上的 Nginx 配置已经正确
            ↓
运行中的 worker 仍使用旧配置
            ↓
restart 重新读取磁盘配置
            ↓
请求恢复正常

“重启前没有修改配置”不代表运行中的 Nginx 已经加载当前磁盘配置。配置可能更早就修改过,但一直没有 reload。

重启还会破坏部分故障现场。问题恢复也可能恰好与 DNS 更新或外部依赖恢复同时发生。下次先保存:

curl -vk https://www.example.com/api/user
curl -i http://127.0.0.1:8080/api/user
pm2 status
pm2 logs nloop --lines 50 --nostream
sudo systemctl status nginx
sudo tail -n 50 /var/log/nginx/access.log
sudo tail -n 50 /var/log/nginx/error.log
sudo nginx -t

记录现场后,优先尝试:

sudo nginx -t && sudo systemctl reload nginx

如果 reload 后恢复,就更有理由判断运行配置此前没有更新。

16. 一套可以照着执行的排查流程

第一步:检查 Express

curl -i http://127.0.0.1:8080/api/user

第二步:检查 PM2

pm2 status
pm2 describe nloop
pm2 logs nloop --lines 50 --nostream

确认应用在线、入口与 Node.js 版本正确,并且没有反复重启。

第三步:检查 Nginx

sudo systemctl status nginx
sudo nginx -t

确认 Nginx 正在运行,磁盘配置语法正确。

第四步:观察域名请求

curl -vk https://www.example.com/api/user

关注实际连接 IP、请求路径、Host 和响应状态。

第五步:检查日志

sudo tail -n 50 /var/log/nginx/access.log
sudo tail -n 50 /var/log/nginx/error.log

把请求时间与日志时间对应起来。

第六步:确认配置后重新加载

sudo nginx -t && sudo systemctl reload nginx

不要跳过配置检查,也不要把 restart 当成第一个排查动作。

17. 进阶:绕过 DNS 测试本机 Nginx

怀疑域名指向错误服务器时,可以执行:

curl -vk \
  --resolve www.example.com:443:127.0.0.1 \
  https://www.example.com/api/user

它的含义是:

URL、Host 和 HTTPS 域名仍使用 www.example.com
但是本次不使用公网 DNS 结果
而是强制连接 127.0.0.1:443

它比直接访问:

curl -k https://127.0.0.1/api/user

更适合测试基于域名的 Nginx 配置。直接使用 IP 会让 Host 和 TLS 域名变成 127.0.0.1,可能命中错误的 server。

如果 --resolve 测试正常,而普通域名请求异常,继续检查:

查看 DNS 地址:

dig +short A www.example.com
dig +short AAAA www.example.com

强制 IPv4 或 IPv6:

curl -4vk https://www.example.com/api/user
curl -6vk https://www.example.com/api/user

如果 IPv4 正常而 IPv6 异常,通常要检查 AAAA 记录及服务器的 IPv6 Nginx 配置。

18. 进阶:让部署脚本识别 HTTP 失败

普通 curl 收到 HTTP 404 时,命令本身仍可能以成功退出码结束,因为网络请求确实完成了。

部署健康检查可以使用:

curl \
  --fail-with-body \
  --silent \
  --show-error \
  --connect-timeout 3 \
  --max-time 10 \
  http://127.0.0.1:8080/health

参数含义:

这是自动部署验证方式,不是第一次人工排查必须掌握的内容。

19. 初学者常见误区

本机 8080 正常,所以 Nginx 一定正常

8080 请求绕过了 Nginx,只能证明 Express 基本正常。

nginx -t 成功,所以新配置已经生效

nginx -t 只检查磁盘文件,还要执行 reload 才能应用。

PM2 显示 online,所以所有接口一定正常

online 只表示进程存在,不代表路由、数据库和业务依赖都正常。

使用 -k 后成功,所以 HTTPS 已修复

-k 只是忽略证书验证,真正的证书问题依然存在。

看到 404 就重启所有服务

重启可能暂时恢复,也可能让错误证据消失。先记录 curl 输出、日志和进程状态。

Server: nginx 说明 404 一定由 Nginx 产生

Express 的响应也可能通过 Nginx 返回,需要结合 Nginx 和应用日志判断。

20. 最后总结

遇到域名访问异常时,先记住这条最短路径:

curl 直接检查 Express
        ↓
检查 PM2 状态和应用日志
        ↓
curl -vk 观察域名请求
        ↓
检查 Nginx 状态、配置和日志
        ↓
确认配置后执行 reload

常用命令汇总:

curl -i http://127.0.0.1:8080/api/user
curl -vk https://www.example.com/api/user

pm2 status
pm2 describe nloop
pm2 logs nloop --lines 50 --nostream

sudo systemctl status nginx
sudo nginx -t
sudo tail -n 50 /var/log/nginx/access.log
sudo tail -n 50 /var/log/nginx/error.log

sudo nginx -t && sudo systemctl reload nginx

真正有价值的不是记住所有命令,而是每次只验证一层,用结果决定下一步,不用重启代替定位。

练习题

  1. curl http://127.0.0.1:8080/api/user 正常,可以证明域名和 Nginx 都正常吗?为什么?
  2. curl -v 输出中的 *>< 分别表示什么?
  3. curl -k 会绕过 Nginx 或用户身份认证吗?它真正忽略的是什么?
  4. 为什么执行 sudo nginx -t 成功后,新配置仍可能没有生效?
  5. Nginx 返回 502,而直接访问 8080 提示连接被拒绝,应该先检查什么?
  6. 直接访问 /api/user 正常,但经过 Nginx 后 Express 收到 /user,应该检查哪个配置细节?
  7. 当前服务器的 Nginx access log 没有请求记录,但域名请求确实返回了页面,可能有哪些原因?
  8. 为什么问题发生时不建议第一时间重启 Nginx 和 PM2?重启前至少应该保存哪些信息?