GCP Ubuntu22虚拟机中Nginx+React+Express配置API 404问题排查
GCP Ubuntu 22虚拟机上Nginx+React+Express配置问题:API请求404错误
已配置防火墙并开启Nginx Full规则与Express API服务器的3005端口,React应用可正常访问,但所有API请求始终返回404错误。
React应用代码
import './App.css'; import { useState } from 'react'; const API_BASE = 'http://mydomain/api/' function App() { const [currentResponse, setCurrentResponse] = useState(null) const makeReqeustToAPI = (route) => { return fetch(`${API_BASE}${route}`) .then(response => response.json()) .then(data => { console.log(data) setCurrentResponse(data) }) .catch(err => console.log(err)) } return ( <div className="App"> <h1>Hello world, I'm a react app...</h1> <div className="button-container"> <button className='btn' onClick={() => { makeReqeustToAPI('') }}>api home route</button> <button className='btn' onClick={() => { makeReqeustToAPI('products') }}>api products route</button> <button className='btn' onClick={() => { makeReqeustToAPI('products/3') }}>api products specific route</button> </div> {currentResponse && <div>{Object.keys(currentResponse).map((key, index) =>{ const item = currentResponse[key] if(typeof item === 'object') { return <h2 key={index}>{`${key}: ${currentResponse[key].value}`}</h2> } else { return <h2 key={index}>{`${key}: ${currentResponse[key]}`}</h2> } })}</div>} </div> ); } export default App;
Express应用代码
const express = require('express') const app = express() const cors = require('cors') const products = { product1: { id: 1, value: 'apple' }, product2: { id: 2, value: 'bannana' }, product3: { id: 3, value: 'salt' }, product4: { id: 4, value: 'yogurt' } } app.use(express.json()) app.use(cors()) app.get('/', (req, res) => { res.json({greeting: 'hello world', type: 'I\'m an express response'}) }) app.get('/products', (req, res) => { res.json({product1: products.product1, product2: products.product2, product3: products.product3, product4: products.product4}) }) app.get('/products/:id', (req, res) => { const id = Number(req.params.id) const item = Object.keys(products).map(key => products[key]).find(product => product.id===id) if(1<2) { res.json({item: products.product1}) } else { res.status(404).send('not found') } }) const PORT = 3005 app.listen(PORT, () => { console.log(`App listening on port ${PORT}`) })
当前Nginx配置
server { listen 80 default_server; listen [::]:80 default_server; root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name _; location / { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. proxy_pass http://localhost:8080; } location /api { proxy_pass http://localhost:3005; } }
问题根源
Nginx的location /api配置会将请求路径原样转发给Express服务。例如:
- React请求
/api/会被转发到http://localhost:3005/api/,但Express的根路由是/,不存在/api路由,导致404。 - 请求
/api/products会被转发到http://localhost:3005/api/products,而Express的路由是/products,路径不匹配。
修复方案
方案1:调整proxy_pass路径(推荐)
修改Nginx配置中的location /api块,在proxy_pass目标末尾添加斜杠:
location /api { proxy_pass http://localhost:3005/; # 添加必要的请求头,确保Express能正确处理请求 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
添加斜杠后,请求/api/products会被转发到http://localhost:3005/products,与Express的路由完全匹配。
方案2:使用rewrite重写路径
如果不希望修改proxy_pass的格式,可以通过rewrite规则剥离/api前缀:
location /api { rewrite ^/api/(.*)$ /$1 break; proxy_pass http://localhost:3005; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
后续检查步骤
- 验证Express服务状态:在虚拟机上执行
curl http://localhost:3005和curl http://localhost:3005/products,确认能正常返回JSON数据。 - 重启Nginx生效配置:执行
sudo systemctl restart nginx。 - 排查日志:若问题仍存在,查看Nginx错误日志
sudo tail -f /var/log/nginx/error.log,定位转发过程中的异常。
内容的提问来源于stack exchange,提问作者jim
相关产品推荐
相关产品推荐

