You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Node.js子域名子目录部署路由失效求助:Cannot POST /sr/user/1

解决子目录下Node.js服务路由失效的问题

嘿,咱们来搞定你在web.example.com/sr子目录下运行Node.js服务时遇到的路由问题!你看到的Cannot POST /sr/user/1错误,核心原因是服务端路由没正确处理/sr这个子路径前缀,同时还要配合React项目的部署配置调整,下面一步步来解决:

1. 给Node.js服务的路由统一加上前缀

不管你用的是Express、Koa还是其他框架,都需要让所有路由识别/sr前缀,这里分两种常用框架举例:

如果你用的是Express:

  • 优雅的方式:用Router统一挂载前缀
    先把所有业务路由定义在Router里,再把Router挂载到/sr路径下,这样不用给每个路由手动加前缀:
    const express = require('express');
    const router = express.Router();
    
    // 这里定义不带前缀的路由,比如原来的/user/:id
    router.post('/user/:id', (req, res) => {
      // 你的业务逻辑代码
      res.json({ message: '处理成功' });
    });
    router.get('/posts', (req, res) => {
      // 其他路由逻辑
    });
    
    // 把整个Router挂载到/sr前缀下
    app.use('/sr', router);
    
  • 简单直接的方式:给每个路由手动加/sr前缀
    如果路由不多,也可以直接修改每个路由的路径:
    // 原来的app.post('/user/:id', ...)改成下面这样
    app.post('/sr/user/:id', (req, res) => {
      // 业务逻辑不变
    });
    

如果你用的是Koa:

koa-routerprefix属性来统一设置前缀:

const Router = require('koa-router');
// 初始化Router时指定前缀为/sr
const router = new Router({ prefix: '/sr' });

router.post('/user/:id', async (ctx) => {
  // Koa的业务逻辑
  ctx.body = { message: '处理成功' };
});

// 把路由注册到app上
app.use(router.routes());

2. 配置React项目的基础路径

因为你要在/sr子目录部署React,得让React知道它的根路径不是域名根目录,而是/sr,不然前端路由会出错:

  • 第一步:修改package.json,添加homepage字段
    这样打包React时,所有静态资源的路径都会自动带上/sr前缀:
    {
      "name": "你的React项目名",
      "homepage": "/sr",
      // 其他原有配置...
    }
    
  • 第二步:给React Router设置basename(如果用了React Router)
    如果你用的是React Router v6+,需要给BrowserRouter加上basename="/sr",让前端路由自动带上前缀:
    import { BrowserRouter, Routes, Route } from 'react-router-dom';
    
    function App() {
      return (
        <BrowserRouter basename="/sr">
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/user/:id" element={<UserDetail />} />
          </Routes>
        </BrowserRouter>
      );
    }
    

3. 处理静态文件托管(如果Node.js要托管React打包文件)

如果你的Node.js服务需要直接托管React打包后的build文件夹,要确保静态文件的路径配置正确:

Express示例:

const path = require('path');

// 托管React的静态资源,路径对应/sr
app.use('/sr', express.static(path.join(__dirname, 'build')));

// 处理SPA的刷新问题:当访问/sr下的任意路由时,返回React的index.html
app.get('/sr/*', (req, res) => {
  res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

4. 检查反向代理配置(如果用了Nginx等)

如果你是用Nginx把请求反向代理到Node.js服务,要确保Nginx不会把/sr前缀去掉,配置示例如下:

server {
  server_name web.example.com;

  location /sr {
    proxy_pass http://localhost:3000; # 这里填你的Node.js服务运行的地址和端口
    proxy_set_header Host $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;
    # 确保请求的URI完整传递给Node服务,不要丢失/sr前缀
    proxy_pass_request_uri on;
  }
}

最后验证一下

修改完这些配置后:

  1. 重启你的Node.js服务
  2. 重新打包React项目(npm run build),把打包后的build文件夹放到对应部署目录
  3. 访问web.example.com/sr应该能正常加载React页面,测试POST请求web.example.com/sr/user/1也能正常触发后端路由啦!

内容的提问来源于stack exchange,提问作者S.M_Emamian

火山引擎 最新活动