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

Express.js路由异常:文档创建成功但catch块仍执行

排查Express.js + Mongoose创建Category接口的404异常问题

问题现象

调用创建Category的接口后出现矛盾现象:

  • MongoDB Compass显示文档已成功写入数据库
  • 接口返回catch块的404错误响应
  • 控制台打印日志:POST /api/categories/ 404 56.973 ms - 99
  • 请求体参数正常传递(控制台已输出req.body = { name: 'Suleyman Sah Furnitures' })

相关代码

server.js

const mongoose = require("mongoose");
const dotenv = require("dotenv");
dotenv.config({ path: "./config.env" });
const app = require("./app");

mongoose
  .connect(process.env.LOCAL_CONN_STRING, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  })
  .then((conn) => {
    console.log(`Connection successfull with : ${conn}`);
  })
  .catch((err) => {
    console.log("error is: ", err);
  });

// 启动服务
app.listen(5000, () => {
  console.log("server has started");
});

app.js

// 导入模块
const express = require("express");
const morgan = require("morgan");

const app = express();
const productsRouter = require("./routes/productsRouter");
const customersRouter = require("./routes/customersRouter");
const employiesRouter = require("./routes/employiesRouter");
const addressesRouter = require("./routes/addressesRouter");
const contactsRouter = require("./routes/contactsRouter");
const categoriesRouter = require("./routes/categoriesRouter");
const subCategoriesRouter = require("./routes/subCategoriesRouter");
const ordersRouter = require("./routes/ordersRouter");
const orderProductsRouter = require("./routes/orderProductsRouter");
const paymentsRouter = require("./routes/paymentsRouter");
const pricesRouter = require("./routes/pricesRouter");
const stocksRouter = require("./routes/stocksRouter");

// 中间件配置
app.use(express.json());
if (process.env.NODE_ENV === "development") {
  app.use(morgan("dev"));
}
app.use(express.static("./public"));
app.use((req, res, next) => {
  req.requestAt = new Date().toISOString();
  next();
});

// 挂载路由
app.use("/api/products", productsRouter);
app.use("/api/customers", customersRouter);
app.use("/api/employies", employiesRouter);
app.use("/api/addresses", addressesRouter);
app.use("/api/contacts", contactsRouter);
app.use("/api/categories", categoriesRouter);
app.use("/api/subcategories", subCategoriesRouter);
app.use("/api/orders", ordersRouter);
app.use("/api/orderproducts", orderProductsRouter);
app.use("/api/payments", paymentsRouter);
app.use("/api/prices", pricesRouter);
app.use("/api/stocks", stocksRouter);

// 全局404处理
app.all("*", (req, res) => {
  res.status(404).json({
    status: "fail",
    data: {
      message: `The requested route (${req.originalUrl}), Not found on the server!`,
    },
  });
});
module.exports = app;

Category控制器

exports.createCategory = async (req, res) => {
  try {
    const { name } = req.body;
    console.log("req.body = ", req.body, "name passsed = ", name);
    const category = await Category.create(
      { name },
      {
        new: true,
        runValidators: true,
      }
    );
    console.log("pass validation", category);
    res.status(200).json({
      status: "success",
      data: {
        category,
      },
    });
  } catch (err) {
    res.status(404).json({
      status: "fail",
      data: {
        error: err.message,
      },
    });
  }
};

Category Schema

const categorySchema = new mongoose.Schema({
     name: {
         type: String,
         required: [true, "category must be specified"],
         minlength: 10,
         maxlength: 100,
         unique: [true, "Category name must be unique"],
      },
  });

控制台日志

[nodemon] starting `node server.js`
server has started
Connection successfull with : [object Object]
req.body =  { name: 'Suleyman Sah Furnitures' } name passsed =  Suleyman Sah Furnitures
POST /api/categories/ 404 56.973 ms - 99

排查步骤

  1. 核对路由定义与请求路径

    • 确认categoriesRouter内是否正确定义了POST /路由(因为app.js中挂载的是/api/categories,所以路由器内应为router.post('/', createCategory)),如果路由路径不匹配,会直接落入全局404处理。
    • 检查categoriesRouter是否正确导出并挂载,确保没有拼写错误。
  2. 分析控制器异常触发逻辑

    • 控制台未打印pass validation日志,说明Category.create()执行后直接进入catch块,尽管MongoDB已写入文档。这种情况大概率是Mongoose在写入后触发了后续异常:
      • 检查Category模型是否存在post钩子(如post('save')),若钩子函数抛出异常,会导致create()的Promise拒绝。
      • 验证unique约束:MongoDB的唯一索引是否已正确创建?若索引创建延迟,可能出现写入成功后Mongoose检测到重复的情况(首次创建时概率较低)。
  3. 检查响应是否被中断或覆盖

    • 测试将控制器内的成功响应改为简单的res.send('test'),排除JSON序列化失败(如category对象存在循环引用)导致的异常。
    • 确认控制器内没有遗漏的next()调用,避免请求流转到全局404路由。
  4. 处理路径末尾斜杠问题

    • 确认请求路径是/api/categories还是/api/categories/,Express默认会自动兼容,但可在categoriesRouter中显式处理两种路径,或启用app.use(express.urlencoded({ extended: true }))优化路径匹配。
  5. 打印完整错误信息

    • 修改catch块,打印完整错误对象而非仅err.message,定位异常根源:
      catch (err) {
        console.error("Full error details:", err);
        res.status(400).json({
          status: "fail",
          data: {
            error: err.message,
            stack: err.stack
          },
        });
      }
      

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 03:17:03