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

使用Chai-Http测试Node+Express+TS接口始终返回404错误

嗨,我来帮你排查下这个全量404的问题!这种情况我碰到过好几次,大概率是测试代码和主App的衔接环节出了问题,咱们一步步拆解:

常见问题排查与解决方案

1. 确保测试代码正确拿到了Express App实例

很多时候问题出在App的导出方式上。如果你的app.ts里直接把启动服务器的listen逻辑和App实例混在一起,测试代码引入时可能会因为异步启动的问题,导致请求发起时路由还没挂载。

正确的拆分方式:

  • app.ts里只负责创建和配置App,最后导出实例:
// app.ts
import express from 'express';
import mongoose from 'mongoose';

export const app = express();

// 中间件配置
app.use(express.json());

// 路由注册(注意不要放在数据库连接的回调里!)
app.use('/api/users', userRoutes);

// 数据库连接逻辑可以单独抽离,或者放在server.ts里
let mongodbURI;
if (process.env.NODE_ENV === "test") {
  mongodbURI = process.env.MONGODB_TEST_URI;
} else {
  mongodbURI = process.env.MONGODB_URI;
}
mongoose.Promise = global.Promise;
mongoose.connect(mongodbURI, { useMongoClient: true });
  • 单独用server.ts处理服务器启动:
// server.ts
import { app } from './app';
const port = process.env.PORT || 3000;

app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});
  • 测试代码里直接引入导出的App实例:
// user.test.ts
import chai from 'chai';
import chaiHttp from 'chai-http';
import { app } from '../src/app';

chai.use(chaiHttp);
const expect = chai.expect;

2. 避免把路由注册放在数据库连接回调里

如果你的路由是在mongoose.connect()的then回调里注册的,测试时请求发起的时机可能早于数据库连接完成,导致路由还没挂载,自然返回404。

错误示例:

// 不要这么做!
mongoose.connect(mongodbURI, { useMongoClient: true })
  .then(() => {
    app.use('/api/users', userRoutes);
  });

修正方式:把路由注册移到数据库连接逻辑之外,数据库连接只负责建立连接,不影响路由挂载。

3. 验证请求路径与实际路由完全匹配

比如你的API前缀是/api,但测试时请求的是/users,或者路由里定义的是/api/users/:id,但测试时传的是/api/user/:id(少了个s),这种拼写错误也会导致404。

测试时要严格对应路由路径:

// 如果实际路由是app.use('/api/users', userRoutes)
chai.request(app)
  .get('/api/users') // 必须写全路径
  .end((err, res) => {
    // ...断言逻辑
  });

4. 确保测试环境的环境变量正确加载

测试时如果没加载测试用的.env文件,可能会导致NODE_ENV不是test,甚至数据库连接失败间接影响路由挂载。可以在测试代码开头手动加载:

// user.test.ts 顶部
import dotenv from 'dotenv';
dotenv.config({ path: '.env.test' }); // 指定测试环境的配置文件

5. 完整测试代码示例

给你一个可参考的测试模板,包含数据库连接的前置钩子:

import chai from 'chai';
import chaiHttp from 'chai-http';
import { app } from '../src/app';
import mongoose from 'mongoose';

chai.use(chaiHttp);
const expect = chai.expect;

describe('Users API', () => {
  // 测试前确保数据库连接完成
  before(async () => {
    await mongoose.connect(process.env.MONGODB_TEST_URI, { useMongoClient: true });
  });

  // 测试后断开数据库连接
  after(async () => {
    await mongoose.disconnect();
  });

  it('should return 200 when fetching all users', (done) => {
    chai.request(app)
      .get('/api/users')
      .end((err, res) => {
        expect(res).to.have.status(200);
        expect(res.body).to.be.an('array');
        done();
      });
  });
});

最后再检查下app.ts里的中间件顺序,别把404 fallback中间件放在路由注册前面,比如这种错误:

// 错误顺序:404中间件在路由前面,所有请求都会返回404
app.use((req, res) => res.status(404).json({ message: 'Not Found' }));
app.use('/api/users', userRoutes);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:28:38