我找到了一种“线程安全”的解决方案,可以在不修改req对象并通过所有层传递数据的情况下实现。因此,我们有
continuation-local-storage包,它允许我们在req的开始绑定req,然后在下一次调用时重复使用。但是当您尝试使用异步调用链时,CLS不是“线程安全的”,如果您尝试在几个并发请求期间调用它,它将失败并丢失“上下文”。因此,我们有
cls-hooked包,可以解决此问题,我们可以轻松地捕获当前上下文绑定请求的请求开始。这是一个使用awilix(依赖注入框架)的小例子,我们将创建“RequestContext”类,并能够在需要的任何地方使用它。让我们创建RequestContext类:
module.exports = class RequestContext {
constructor(req, res, dependencies) {
const { myService1, myService2 } = dependencies;
this.req = req;
this.res = res;
}
getMyTestHeader() {
return this.req.headers.testHeader;
}
这是一个简单的“请求包装器”。如果需要,它会消耗请求、响应和其他依赖项,并提供 getMyTestHeader 以在类外使用。
让我们在请求开始时(在所有其他中间件之前)创建中间件:
const clsNamespace = require('cls-hooked').createNamespace('my-per-request-session');
app.use((req, res, next) => {
clsNamespace.bind(req);
clsNamespace.bind(res);
clsNamespace.run(() => {
clsNamespace.set('req', req);
clsNamespace.set('res', res);
next();
});
});
现在,让我们使用 awilix 注册 DI 调用:
container.register({
requestContextProvider: asFunction(dependencies => ({
getCurrentContext: () => {
const req = dependencies.clsNamespace.get('req');
const res = dependencies.clsNamespace.get('res');
return new RequestContext(req, res, dependencies);
},
})),
因此,我们将requestContextProvider注册为函数,每次DI依赖项调用时都会在外部上下文(cls)中使用req和res进行实例化。
结果,我们可以这样使用它(例如在控制器中):
module.exports = (dependencies) => ({
myControllerAction: async (req, res) => {
const {requestContextProvider} = dependencies;
const requestContext = requestContextProvider.getCurrentContext();
const myHeader = requestContext.getMyTestHeader();
res.status(200).json({ myHeader });
},
});
正如您所看到的,现在我们可以在每个层级(控制器/BLL/DAL/helpers等)访问DI时都有“requestContext”。因此,它是“线程安全”的,易于测试,并且不需要将req对象传递到所有“中间”层。
同意,这不是最好和最简单的示例,但希望能对某些人有所帮助。
process.domain = reqd;
对我很有用。不幸的是,我找不到文件来描述它的行为 :-/ - Timmnext()
,而是调用reqd.run(next)
。enter
方法是由run
、bind
和intercept
方法使用的管道,用于设置活动域。它将domain.active
和process.domain
设置为该域。http://nodejs.org/api/domain.html#domain_domain_enter - Ricardo Stuven