You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

后续检查步骤

  1. 验证Express服务状态:在虚拟机上执行curl http://localhost:3005和curl http://localhost:3005/products,确认能正常返回JSON数据。
  2. 重启Nginx生效配置:执行sudo systemctl restart nginx。
  3. 排查日志:若问题仍存在,查看Nginx错误日志sudo tail -f /var/log/nginx/error.log,定位转发过程中的异常。

内容的提问来源于stack exchange,提问作者jim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:35:00