Express中间件失效及浏览器无响应问题求助(疑因文件结构)
问题背景
我正在学习Express中间件开发,实现了一个记录访问URL到控制台的logger中间件。一开始把端点都写在同一个文件时,中间件正常工作;但拆分每个端点到单独文件后,中间件无法记录URL,浏览器也看不到预期响应。本人有Java开发经验,刚接触TypeScript,需要解决这个问题,实现浏览器显示响应、控制台记录访问URL的目标。
文件结构

原代码
index.ts
import express from 'express'; import logger from './utilities/logger'; import route from './routes/index' const app = express(); const port = 3002; app.use('/sport', route) app.listen(port, () => { console.log(`server started at http://localhost:${port}`); });
logger.ts
import express from 'express'; const logger = (req: express.Request, res: express.Response, next: Function): void => { const url = req.url; console.log(`${url} was visited - hello`); // next(); } export default logger;
routes/index.ts
import express from 'express'; import football from './api/football' import basketball from './api/basketball' import skiing from './api/skiing' const route = express.Router(); route.get('/', (_req, _res) => { _res.send("Main route file"); }); route.use('/basketball', basketball); route.use('/football', football); route.use('/skiing', skiing); export default route;
basketball.ts
import express from 'express'; import logger from '../../utilities/logger'; const route = express.Router(); route.get('/', logger,(_req, _res) => { _res.send('bball!'); }); export default route;
football.ts
import express from 'express'; import logger from '../../utilities/logger'; const route = express.Router(); route.get('/', logger,(_req, _res) => { _res.send('footie!'); }); export default route;
问题原因
核心问题在logger.ts里:next()被注释掉了。Express中间件的核心逻辑是,处理完自身任务后必须调用next(),才能把请求传递给后续的处理函数(比如路由里的响应发送逻辑)。如果不调用next(),请求会被挂起,既不会触发后续的响应输出,也不会继续处理流程,导致浏览器一直等待响应,同时后续逻辑也无法执行。
另外,原代码里用req.url只能拿到当前路由层级的路径(比如访问/sport/basketball时,req.url是/),如果想记录完整的访问路径,应该用req.originalUrl。
解决方案
1. 修复logger中间件
取消next()的注释,同时把req.url改为req.originalUrl以记录完整路径:
import express from 'express'; const logger = (req: express.Request, res: express.Response, next: express.NextFunction): void => { const url = req.originalUrl; console.log(`${url} was visited - hello`); next(); // 必须调用next传递请求 } export default logger;
2. 优化路由结构(可选)
如果想让logger对所有请求生效,不用在每个路由文件里单独引入,可以在index.ts全局挂载中间件,这样所有请求都会经过logger:
import express from 'express'; import logger from './utilities/logger'; import route from './routes/index' const app = express(); const port = 3002; app.use(logger); // 全局挂载,所有请求都会触发logger app.use('/sport', route) app.listen(port, () => { console.log(`server started at http://localhost:${port}`); });
此时,各个路由文件可以去掉logger的引入,简化代码,比如basketball.ts:
import express from 'express'; const route = express.Router(); route.get('/', (_req, _res) => { _res.send('bball!'); }); export default route;
测试效果
访问http://localhost:3002/sport/basketball,控制台会输出/sport/basketball was visited - hello,浏览器显示bball!;访问http://localhost:3002/sport/football,控制台输出对应完整URL,浏览器显示footie!,完全符合预期。
内容的提问来源于stack exchange,提问作者Othello

