如何将中间件中的值传递给后续控制器(Token认证场景)
如何将中间件中的值传递给后续控制器(Token认证场景)
兄弟我懂你这种挠头的感觉!之前我也遇到过类似的情况,在非Express的环境里没法直接用req.user或者res.locals,确实头疼。针对你这种Token认证后传递用户数据的需求,给你几个靠谱的方案,不用在每个控制器里重复调用函数:
利用Node.js原生的Async Local Storage实现请求上下文
这是个通用型的方案,不管你用什么Node.js框架都能用上。它能在整个异步调用链中保存上下文数据,完美解决跨中间件、跨控制器的传值问题。举个实际代码例子:// 初始化Async Local Storage const { AsyncLocalStorage } = require('async_hooks'); const als = new AsyncLocalStorage(); // 认证中间件:解析Token并存储用户数据 const authMiddleware = async (req, res, next) => { // 这里替换成你的Token验证逻辑,解析出用户数据 const userData = await verifyToken(req.headers.authorization?.split(' ')[1]); // 启动上下文并存储用户数据 als.run(new Map(), () => { als.getStore().set('currentUser', userData); next(); // 放行到后续控制器 }); }; // 任意控制器中获取用户数据 const getUserProfileController = (req, res) => { const currentUser = als.getStore().get('currentUser'); res.json({ userId: currentUser.id, username: currentUser.username }); };这种方式不用修改请求/响应对象,而且在任何异步嵌套的函数里都能拿到用户数据,非常灵活。
自定义扩展请求对象
如果你的框架允许自定义请求对象(比如Fastify、Koa都有类似机制),可以参照Express的req.user思路,给请求对象添加自定义属性。比如:// 自定义请求类(以某框架为例) class CustomRequest extends FrameworkBaseRequest { constructor(rawReq) { super(rawReq); this.currentUser = null; // 预留用户属性 } } // 在框架配置中替换默认请求类为自定义类 frameworkInstance.config({ requestClass: CustomRequest }); // 认证中间件中赋值 const authMiddleware = async (req, res, next) => { const userData = await verifyToken(req.headers.authorization?.split(' ')[1]); req.currentUser = userData; // 直接给自定义请求对象赋值 next(); }; // 控制器中直接使用 const orderListController = (req, res) => { console.log(`获取用户${req.currentUser.id}的订单列表`); // 业务逻辑... };这个方案最贴近你熟悉的Express用法,学习成本低,代码也直观。
借助依赖注入(DI)实现解耦传递
如果你的项目是大型架构,用了依赖注入框架(比如TypeDI、NestJS的DI系统),可以把用户数据注入到需要的控制器中,彻底解耦中间件和控制器:// 认证中间件:将用户数据绑定到请求作用域的DI容器 const authMiddleware = async (req, res, next) => { const userData = await verifyToken(req.headers.authorization?.split(' ')[1]); // 以TypeDI为例,绑定请求作用域的用户实例 container.register({ id: 'CurrentUser', useValue: userData }, { scope: Scope.Request }); next(); }; // 控制器通过DI注入用户数据 class UserController { constructor(@Inject('CurrentUser') private currentUser) {} async getProfile(req, res) { res.json({ id: this.currentUser.id, email: this.currentUser.email }); } }这种方式适合追求代码架构整洁、可测试性高的项目,控制器不用关心用户数据从哪来,只需要用就行。
你可以根据自己项目所用的框架、规模大小来选择合适的方案,都能完美解决你不想重复调用函数的痛点。
备注:内容来源于stack exchange,提问作者Waqas Akbar
相关产品推荐
相关产品推荐

