如何在Express中间件与端点之间共享信息?
解决多个中间件共享数据源的冗余问题
嘿,这个痛点我太懂了!当多个中间件都需要从同一个地方(比如数据库)拿相同的资源信息时,每次都重复写stateAsync这类函数不仅代码冗余,后期改逻辑还要挨个找地方改,简直是维护噩梦。下面给你几个实用的解决方案,按需挑选:
1. 抽离共享逻辑为独立函数
最直接的办法就是把重复的数据源查询逻辑单独拎出来,做成一个可复用的函数,然后在所有需要的中间件里引用它:
// 单独抽离的共享资源状态获取函数 async function fetchResourceState(req) { // 这里写你的数据库查询逻辑,比如根据请求参数拿资源的最后修改时间 const targetResource = await db.resources.findOne({ where: { id: req.params.resourceId } }); return { lastModified: targetResource.updatedAt }; } // 在各个中间件里直接复用这个函数 app.use(preconditions({ stateAsync: fetchResourceState })); // 假设有另一个需要相同信息的缓存中间件 app.use(cacheControlMiddleware({ getResourceState: fetchResourceState }));
这样一来,所有中间件共用同一套逻辑,后期要修改查询规则(比如加权限校验、换数据源),只需要改这一个函数就行,省心太多。
2. 请求周期内挂载共享数据
如果多个中间件是在同一个请求流程里需要用到相同资源数据,那可以提前在前置中间件里查询一次,把结果挂载到req对象上,后续中间件直接用,避免重复查询数据库(性能提升很明显):
// 前置中间件:提前获取资源状态并挂载到req app.use(async (req, res, next) => { try { // 只查一次数据库 req.resourceState = await db.resources.findOne({ where: { id: req.params.resourceId } }); next(); // 继续执行后续中间件 } catch (error) { next(error); // 一定要处理异步错误,避免请求挂起 } }); // 后续中间件直接用req上的缓存数据 app.use(preconditions({ stateAsync: (req) => Promise.resolve(req.resourceState) })); // 另一个中间件同理,不用再查数据库 app.use(etagMiddleware({ getResource: (req) => req.resourceState }));
⚠️ 注意:如果你的业务场景中,资源状态可能在同一个请求周期内被修改(比如前面的中间件更新了资源),那这种方式就不适用了,得重新查询。
3. 封装中间件工厂的包装器
如果有一堆中间件的配置结构相似,都需要注入同一个共享选项,可以写一个包装函数,自动帮你把共享配置注入到中间件工厂里:
// 包装器函数:自动注入共享的stateAsync配置 function withResourceState(middlewareFactory) { return middlewareFactory({ stateAsync: async (req) => { const targetResource = await db.resources.findOne({ where: { id: req.params.resourceId } }); return { lastModified: targetResource.updatedAt }; } }); } // 使用的时候直接调用包装器,不用重复写配置 app.use(withResourceState(preconditions)); app.use(withResourceState(anotherMiddlewareThatNeedsState));
这种方式适合项目里有多个同类型中间件的场景,能进一步简化代码,减少重复的配置代码。
额外小贴士
- 异步操作一定要做好错误捕获:不管是抽离函数还是前置中间件,都要处理数据库查询失败的情况,避免未处理的Promise拒绝导致服务崩溃。
- 大型项目可以考虑依赖注入:如果你的项目比较复杂,资源获取逻辑还涉及其他服务(比如缓存、权限校验),可以用依赖注入工具来管理这些共享服务,让代码更解耦,测试也更方便。
内容的提问来源于stack exchange,提问作者Anders
相关产品推荐
相关产品推荐

