Как домены nodejs на самом деле работают за кулисами для нескольких запросов?
Мой вариант использования требует, чтобы домены 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
В контроллере / сервисе - process.domain предоставит вам созданный выше домен и вы сможете легко привязать значения к этому домену. Например:
process.domain.obj = {};
Это объяснение достаточно, чтобы понять использование доменов.
Вопросы
Безопасно ли использовать домены для нескольких запросов?
Как убедиться, что process.domain отличается для разных запросов и не одинаково?
Также хотелось бы узнать, как такие проблемы решаются при продолжении локального хранения
1 ответ
Предупреждение
Прежде всего - домены устарели и будут удалены в следующем выпуске NodeJS. Я бы не писал новый код используя их.
Как работают домены?
Во-вторых, важно понимать, что домены - это не волшебство. Они действительно простая концепция. В основном они:
- Оберните каждый асинхронный вызов в платформе (все API-интерфейсы NodeJS).
- Установите "глобальную" переменную на время разговора.
- Если во время этого вызова был сделан другой асинхронный вызов - запомните, чтобы при вводе глобальной переменной было установлено то же значение.
- Вот и все.
Вот как можно реализовать домены, давайте реализовывать их только для 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
в начале, а затем все методы, вызываемые в запросе, будут работать, поскольку все они обернуты, как в примере выше (так как он снова запекается в самом узле).
Это звучит зыбко, зачем убирать их?
Их удаляют из-за сложности реализации, которую они добавляют, а также из-за утечки и восстановления после ошибок в некоторых случаях, когда это не работает.
Так что мне делать?
У вас есть альтернативы, например, обещания синей птицы .bind
который приносит контекст цепочки обещаний, который является менее протекающим способом сделать это.
Тем не менее, я бы просто избегал неявного глобального контекста. Это усложняет рефакторинг, делает неявными зависимости и затрудняет анализ кода. Я просто передаю релевантный контекст объектам, когда создаю их (внедрение зависимости, в двух словах), а не задаю глобальную переменную.