CommonJS 中无法直接使用全局中间件,应通过模块导出工厂函数、应用级统一注册或 Router 链式复用实现复用;禁止挂载到 global 或 process,须保持模块封装性与可配置性。

CommonJS 是 Node.js 默认的模块系统,它本身不支持真正的“全局中间件”,但可以通过模块导出函数、在应用初始化时统一注册,或借助框架(如 Express)的机制实现跨路由复用。关键不是把它挂到全局对象上,而是设计成可注入、可配置、易复用的中间件工厂函数。
封装为可配置的中间件工厂函数
把中间件逻辑写成一个返回中间件函数的工厂函数,这样既能接收配置参数,又保持闭包隔离,避免污染全局作用域。
- 创建 middleware/auth.js:
module.exports = function createAuthMiddleware(options = {}) {
const { requiredRoles = ['user'], failHandler = (req, res) => res.status(403).json({ error: 'Forbidden' }) } = options;
<p>return function authMiddleware(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return failHandler(req, res);</p><pre class="brush:php;toolbar:false;">try {
const decoded = jwt.verify(token, options.secret || 'your-secret');
if (requiredRoles.includes(decoded.role)) {
req.user = decoded;
next();
} else {
failHandler(req, res);
}
} catch (err) {
failHandler(req, res);
}}; };
- 在路由文件中按需使用:
// routes/user.js
const express = require('express');
const router = express.Router();
const createAuthMiddleware = require('../middleware/auth');
<p>// 只有管理员能访问
router.get('/admin', createAuthMiddleware({ requiredRoles: ['admin'] }), (req, res) => {
res.json({ message: 'Admin only' });
});</p><p>module.exports = router;</p>
统一注册到 Express 应用实例
如果多个路由都需要同一类中间件(比如日志、错误处理、CORS),应在 app.js 或主入口文件中一次性注册,而不是每个路由文件里重复调用。
- 示例:统一添加请求日志中间件
// middleware/logger.js
module.exports = function logger(req, res, next) {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl}`);
next();
};
// app.js
const express = require('express');
const logger = require('./middleware/logger');
const userRouter = require('./routes/user');
const postRouter = require('./routes/post');
<p>const app = express();</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill3430" title="Alibabacloud Sdk Client Initialization For Java"><img
src="https://img.php.cn/upload/skill/000/000/081/178955835420587.jpg" alt="Alibabacloud Sdk Client Initialization For Java" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill3430" title="Alibabacloud Sdk Client Initialization For Java" class="overflowclass">Alibabacloud Sdk Client Initialization For Java</a>
<p class="overflowclass">在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。</p>
</div>
<a rel="nofollow" href="/xiazai/skill3430" title="Alibabacloud Sdk Client Initialization For Java" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><p>app.use(logger); // 全局生效(所有路由前执行)
app.use('/api/users', userRouter);
app.use('/api/posts', postRouter);</p>
通过 Router 中间件链式复用
利用 Express 的 Router.use() 在子路由层面复用中间件,适合按业务域分组管理。
- 在路由模块内部统一挂载中间件
// routes/api.js
const express = require('express');
const router = express.Router();
const createAuthMiddleware = require('../middleware/auth');
<p>// 对整个 /api 下的所有子路由启用基础鉴权
router.use(createAuthMiddleware({ requiredRoles: ['user'] }));</p><p>// 子路由无需再单独写中间件
router.use('/users', require('./user'));
router.use('/posts', require('./post'));</p><p>module.exports = router;</p>
避免误用 global 或 process 挂载
不要把中间件赋值给 global.myMiddleware 或 process.myMiddleware —— 这会破坏模块封装性,导致状态混乱、难以测试、无法热更新。
- ❌ 错误做法:
// 不要这样做!
global.authMiddleware = function(req, res, next) { /* ... */ };
- ✅ 正确思路:靠模块导入 + 函数调用 + 框架生命周期控制作用域
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










