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

生产环境下MERN App返回index.html而非数据问题排查

生产模式下API接口返回index.html而非数据的问题

问题描述

生产模式下调用API接口未返回数据,仅得到index.html。相关后端路由及生产环境配置代码如下:

app.use("/api/auth", authRoute);
app.use("/api/users", userRoute);
app.use("/api/movies", movieRoute);
app.use("/api/lists", listRoute);
app.use("/api/check-existance", verify);
app.use("/api/matches", matchRoute);
app.use("/api/categories", categoryRoutes);
app.use("/api/subCategories", subCategoryRoutes);
app.use("/api/competetions", competetionRoutes);
app.use("/api/stream", videos);

if (process.env.NODE_ENV === "production") {
  app.use(express.static(path.join(__dirname, "../client/build")));

  app.get("/*", (req, res) => {
    res.sendFile(path.join(__dirname, "../client", "build", "index.html"));
  });
} else {
  app.get("/", (req, res) => res.send("Please set to production"));
}

问题原因

Express路由按注册顺序匹配,第一个匹配的路由会执行处理逻辑并终止后续匹配。你生产环境中最后注册的app.get("/*")会匹配所有GET请求,包括以/api开头的API请求,导致这些请求被拦截,返回了前端的index.html文件。

解决办法

调整全局GET路由的匹配规则,排除所有API路径,让API路由能正常被匹配:

方案一:路径前缀判断

修改生产环境的全局路由逻辑,只处理非API开头的GET请求:

app.use("/api/auth", authRoute);
app.use("/api/users", userRoute);
app.use("/api/movies", movieRoute);
app.use("/api/lists", listRoute);
app.use("/api/check-existance", verify);
app.use("/api/matches", matchRoute);
app.use("/api/categories", categoryRoutes);
app.use("/api/subCategories", subCategoryRoutes);
app.use("/api/competetions", competetionRoutes);
app.use("/api/stream", videos);

if (process.env.NODE_ENV === "production") {
  app.use(express.static(path.join(__dirname, "../client/build")));

  app.get("/*", (req, res) => {
    // 仅处理非/api开头的请求
    if (!req.path.startsWith('/api')) {
      res.sendFile(path.join(__dirname, "../client", "build", "index.html"));
    }
    // API请求会继续匹配前面的路由
  });
} else {
  app.get("/", (req, res) => res.send("Please set to production"));
}

方案二:正则表达式匹配

用正则直接匹配非/api开头的路径,写法更简洁:

if (process.env.NODE_ENV === "production") {
  app.use(express.static(path.join(__dirname, "../client/build")));

  // 匹配所有不以/api开头的GET请求
  app.get(/^(?!\/api).*$/, (req, res) => {
    res.sendFile(path.join(__dirname, "../client", "build", "index.html"));
  });
} else {
  app.get("/", (req, res) => res.send("Please set to production"));
}

额外提示

  • 若API存在POST/PUT/DELETE等其他HTTP方法的请求,当前代码不会影响,但如果后续添加全局app.all("/*")路由,需同样做API路径排除处理。
  • 确认express.static指向的client/build目录存在且包含正确的前端编译文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 17:25:19