nodejs 域实际上如何在多个请求的幕后工作?
How nodejs domains actually work behind the scenes for multiple requests?
我的用例需要 node.js 域在请求级别跨服务器文件共享信息。
express.js
中的示例实现
domain = require('domain');
app.use(function(req, res, next) {
var reqDomain = domain.create();
reqDomain.add(req);
reqDomain.add(res);
reqDomain.run(next);
});
更多解释见 Nodejs Domains Explicit Binding
在控制器/服务 -
process.domain 将为您提供上面创建的域
您可以轻松地将值绑定到该域。例如:
process.domain.obj = {};
这个解释足以理解域的用法。
问题
对多个请求使用域安全吗?
如何确保process.domain对于不同的请求是不同的而不是相同的?
是如何处理这些问题的
警告
首先 - 域已被弃用,并将在即将发布的 NodeJS 版本中删除。我不会使用它们编写新代码。
域如何运作?
其次 - 重要的是要了解域名不是魔法。它们真的是一个简单的概念。基本上,他们:
- 包装平台中的每个异步调用(整个 NodeJS API)。
- 在通话期间设置一个“全局”变量。
- 如果在该调用期间正在进行另一个异步调用 - 请注意在输入时将全局变量设置为相同的值。
- 就是这样。
这是实现域的方法,为了简单起见,我们只为 setTimeout
实现它。
const oldTimeout = setTimeout;
setTimeout = function(fn, ms) { // also ...args, but let's ignore that
var trackedDomain = domain;
oldTimeout(function() {
var oldDomain = domain; // preserve old context
domain = trackedDomain; // restore context to "global" variable
fn(); // call the function itself
domain = oldDomain; // restore old context
}, ms); // that's it!
};
像 express
这样的东西可以在开始时只做 domain = new RequestContext
然后请求中调用的所有方法都可以工作,因为它们都像上面的例子一样被包装了(再一次,它被烘烤了进入节点本身)。
听起来不错,为什么要删除它们?
它们被删除是因为它们增加了实现的复杂性,而且它们存在漏洞,错误恢复在极端情况下不起作用。
那我该怎么办?
您有其他选择,例如 bluebird promises 有 .bind
,它带来了 promise 链上下文,这是一种不太容易泄漏的方法。
也就是说,我会完全避免隐式全局上下文。它使重构变得困难,使依赖关系隐含,并使代码更难推理。我只是在创建对象时将相关上下文传递给对象(简而言之,依赖注入),而不是设置全局变量。
我的用例需要 node.js 域在请求级别跨服务器文件共享信息。
express.js
中的示例实现domain = require('domain');
app.use(function(req, res, next) {
var reqDomain = domain.create();
reqDomain.add(req);
reqDomain.add(res);
reqDomain.run(next);
});
更多解释见 Nodejs Domains Explicit Binding
在控制器/服务 - process.domain 将为您提供上面创建的域 您可以轻松地将值绑定到该域。例如:
process.domain.obj = {};
这个解释足以理解域的用法。
问题
对多个请求使用域安全吗?
如何确保process.domain对于不同的请求是不同的而不是相同的?
警告
首先 - 域已被弃用,并将在即将发布的 NodeJS 版本中删除。我不会使用它们编写新代码。
域如何运作?
其次 - 重要的是要了解域名不是魔法。它们真的是一个简单的概念。基本上,他们:
- 包装平台中的每个异步调用(整个 NodeJS API)。
- 在通话期间设置一个“全局”变量。
- 如果在该调用期间正在进行另一个异步调用 - 请注意在输入时将全局变量设置为相同的值。
- 就是这样。
这是实现域的方法,为了简单起见,我们只为 setTimeout
实现它。
const oldTimeout = setTimeout;
setTimeout = function(fn, ms) { // also ...args, but let's ignore that
var trackedDomain = domain;
oldTimeout(function() {
var oldDomain = domain; // preserve old context
domain = trackedDomain; // restore context to "global" variable
fn(); // call the function itself
domain = oldDomain; // restore old context
}, ms); // that's it!
};
像 express
这样的东西可以在开始时只做 domain = new RequestContext
然后请求中调用的所有方法都可以工作,因为它们都像上面的例子一样被包装了(再一次,它被烘烤了进入节点本身)。
听起来不错,为什么要删除它们?
它们被删除是因为它们增加了实现的复杂性,而且它们存在漏洞,错误恢复在极端情况下不起作用。
那我该怎么办?
您有其他选择,例如 bluebird promises 有 .bind
,它带来了 promise 链上下文,这是一种不太容易泄漏的方法。
也就是说,我会完全避免隐式全局上下文。它使重构变得困难,使依赖关系隐含,并使代码更难推理。我只是在创建对象时将相关上下文传递给对象(简而言之,依赖注入),而不是设置全局变量。