使用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
相关产品推荐
相关产品推荐

