线上环境POST请求返回504错误但本地运行正常的技术排查求助
问题场景
我用Next.js、Node.js、Nodemailer、Axios和Nginx搭建了一个带联系表单的项目,本地localhost环境下POST请求能正常发送邮件,但部署到DigitalOcean线上后就出问题了:点击提交按钮毫无反应,60秒后返回504超时状态码。换成Fetch替代Axios测试,问题依然存在——只有POST请求异常,GET请求到/api/submit能正常返回JSON数据。
排查过程
查看Nginx日志定位问题
从日志里看到明确的超时提示:2021/02/27 13:59:35 [error] 95396#95396: *3368 upstream timed out (110: Connection timed out) while reading response header from upstream, client: my.ip, server: website.com, request: "POST /api/submit HTTP/1.1", upstream: "http://127.0.0.1:3000/api/submit", host: "website.com", referrer: "https://website.com/contact"这说明请求已经到达Nginx,但上游的Next.js服务迟迟没返回响应。
排除网络层面问题
用Telnet测试了SMTP主机(smtp.gmail.com)和端口(587),连接完全正常,排除了服务器防火墙或网络阻塞的可能。验证Nodemailer配置有效性
试着把后端代码里的process.env.USER和process.env.PASS直接替换成实际的邮箱账号密码,重新部署后居然能正常发邮件了——这直接指向了环境变量未正确加载的问题。
根本原因
因为.env文件通常会被加入.gitignore,克隆GitHub仓库时这个文件并没有同步到服务器上。而Next.js在执行npm run build时,会把代码中的process.env变量静态替换为实际值,服务器上没有.env文件,导致构建后的代码里process.env.USER和process.env.PASS都是undefined,Nodemailer无法完成SMTP认证,一直卡在连接环节,最终导致请求超时。
解决方案
在服务器的项目根目录创建
.env文件,填入正确的环境变量:USER=your-gmail-account@gmail.com PASS=your-app-specific-password提示:如果使用Gmail且开启了两步验证,一定要用应用专用密码,而不是账号的原始密码。
重新执行构建命令,让Next.js重新替换环境变量:
npm run build重启Next.js服务和Nginx,确保新的构建生效:
# 重启Next.js服务(根据你的进程管理工具调整,比如pm2) pm2 restart your-next-app # 重启Nginx sudo systemctl restart nginx
代码优化建议
顺便提一下后端代码里的小疏漏:transporter.sendMail的回调中只处理了成功情况,没有处理错误场景,这会导致请求在出错时一直挂着,建议补充错误响应:
transporter.sendMail(mail, (err, data) => { if (!err) { res.json({ status: "success" }) res.end(); } else { // 补充错误响应,避免请求无意义等待 res.status(500).json({ status: "error", message: err.message }) res.end(); } })
内容的提问来源于stack exchange,提问作者David Pierson

