Nginx部署Angular+Node.js站点POST 404错误排查求助
问题现象
部署在Nginx上的Angular+Node.js网站,其余功能正常,但多语言联系页面提交表单时出现POST 404错误(如请求https://example.com/en/contact返回404),本地开发环境无此问题。
错误原因分析
1. Nginx路由转发逻辑冲突
Nginx原配置中location /块同时使用try_files和proxy_pass,导致POST请求被优先当作静态资源处理。try_files $uri $uri/ /index.html =404会先尝试匹配静态文件,找不到则返回Angular的SPA入口index.html,但POST请求并非静态资源,且try_files的内部重定向会跳过proxy_pass,使得Node.js后端无法接收请求,最终返回404。
2. 前端请求URL域名不一致
EmailService中getBaseUrl()方法混用test.com和example.com域名,实际部署域名是example.com,这会导致请求发送到错误域名,或触发潜在的跨域问题。
3. Node.js路由未被正确触发
虽然Node.js后端路由/:lang/:contact能匹配/en/contact这类路径,但因Nginx未正确转发POST请求,该路由根本不会被执行。
解决方法
步骤1:调整Nginx配置,分离API与静态资源路由
修改Nginx的server块,单独配置API请求转发规则,确保联系表单的POST请求优先发送到Node.js服务,静态资源和SPA路由由Nginx直接处理。
修改后的Nginx配置:
server { listen 80; listen [::]:80; listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate_key /etc/nginx/ssl-certificates/ssl; ssl_certificate /etc/nginx/ssl-certificates/crt; server_name example.com www1.example.com; root /path/to/filex/; access_log /path/to/acc/logs; error_log /path/to/err/logs; if ($scheme != "https") { rewrite ^ https://$host$uri permanent; } location = / { return 301 /en/home; } # 专门处理联系表单的POST请求 location ~ ^/(en/contact|de/kontakt)$ { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $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_set_header Host $http_host; proxy_pass_request_headers on; proxy_connect_timeout 900; proxy_send_timeout 900; proxy_read_timeout 900; } # 处理静态资源与SPA路由 fallback location / { try_files $uri $uri/ /index.html; } location ~ /.well-known { auth_basic off; allow all; } index index.html; }
步骤2:统一前端请求域名
修改EmailService中的getBaseUrl()方法,确保所有请求指向正式部署域名,或使用相对路径避免硬编码:
private getBaseUrl(): string { const lang = this.languageService.getCurrentLanguage(); switch (lang) { case 'en': return '/en/contact'; case 'de': return '/de/kontakt'; default: return '/en/contact'; } }
步骤3:优化Node.js路由(可选)
为API路由添加统一前缀/api,避免与前端路由冲突,同时简化Nginx配置:
- 修改Node.js路由:
app.post('/api/:lang/contact', async (req, res) => { try { const {name,email,phone,message} = req.body; const {lang} = req.params; await transporter.sendMail({ from: `${email}`, to: 'email', subject: `Порака од веб страната`, html: `<div style="font-size: 20px;"> <div><b></b> ${name}</div> <div><b></b> ${phone}</div> <div><b></b> ${email}</div> <div><b></b> ${message}</div>` }); res.status(200).json({ message: 'Email sent successfully'}); } catch(error) { console.error('Error sending email:', error); res.status(500).send('Error sending email') } });
- 修改前端请求路径:
private getBaseUrl(): string { const lang = this.languageService.getCurrentLanguage(); switch (lang) { case 'en': return '/api/en/contact'; case 'de': return '/api/de/contact'; default: return '/api/en/contact'; } }
- Nginx新增API转发规则:
location /api/ { proxy_pass http://127.0.0.1:3000/api/; proxy_http_version 1.1; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $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_set_header Host $http_host; proxy_pass_request_headers on; }
步骤4:重启服务验证
- 执行
nginx -s reload重新加载Nginx配置。 - 重启Node.js后端服务。
- 提交联系表单,检查网络请求是否返回200状态码,邮件是否正常发送。
内容的提问来源于stack exchange,提问作者Marine

