本文将介绍一种简洁且可维护的 Express 开发模式——通过函数式导出(function-based export),将全局配置(如 API 基础 URL)从主应用文件安全、显式地注入到模块化路由文件中,彻底告别全局变量和重复定义带来的困扰,提升代码可维护性。
在 Express 多路由项目中,为保持代码清晰易维护,开发者通常将路由逻辑拆分为独立文件(如 routes/test.js),并通过 app.use() 挂载。然而,当多个路由需共用同一配置(如 url = "https://example.com/v1")时,若直接在路由文件中硬编码,会破坏单一数据源原则;若使用全局变量(如 global.url),则违背模块封装性,导致测试和扩展困难。
如何解决?推荐采用工厂函数模式(Factory Function Pattern):将路由模块导出为一个接收配置参数的函数,返回配置完成的 Router 实例。此方案使依赖关系显式化,便于灵活复用和单元测试,是 Express 中管理配置传递的推荐方式。
✅ 标准实现方式如下:
app.js 中初始化并传入参数:
const express = require("express");
const app = express();
const port = 3000;
const url = "https://example.com/v1";
// 将 url 作为参数传入路由工厂函数
const testRouter = require("./routes/test")(url);
app.use(express.json());
app.use("/test", testRouter); // 注意:必须调用 app.use() 挂载路由
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
routes/test.js 中定义可配置路由模块:
const express = require("express");
const router = express.Router();
// 导出工厂函数,接收外部配置
module.exports = (baseUrl) => {
// 可选:添加共享中间件(如日志)
router.use((req, res, next) => {
console.log("[Test Router] Time:", Date.now());
next();
});
// 使用传入的 baseUrl
router.post("/", (req, res) => {
console.log("Base URL used:", baseUrl);
res.json({ success: true, apiBaseUrl: baseUrl });
});
return router; // 必须返回配置后的 router 实例
};
⚠️ 关键注意事项:
- 路由文件必须导出函数(而非直接导出 router),否则参数无法传递;
- app.use() 的挂载语句不可省略,且路径前缀(如 /test)应与业务语义保持一致;
- 若共享值不止一个(如 url、timeout、authToken),可统一打包为配置对象传入:require("./routes/test")({ url, timeout: 5000 });
- 该模式天然支持环境隔离——开发环境与生产环境传入不同 baseUrl,无需条件判断。
这套方案兼顾模块化、可测试性与可读性,是 Express 官方文档推荐的高级组织方式之一,尤其适合中大型项目在持续演进中使用。
