问题:
有没有办法在每个会话/http请求中创建变量存储?该变量必须是全局可访问的,并且每个 HTTP 请求/连接/会话都不同,并且不需要在函数之间传递。
举个例子(只是为了说明):
setVariableThatCanBeAccessedByThisHTTPRequestOnly( 'a string data' );
任何东西都应该有效,但我宁愿远离将其从一个函数传递到另一个函数。
//I'm trying to get rid of passing req parameter to all custom functions.
//I'd like to store it in a variable somehow, that it can be accessed globally, but only within that session/request.
exports.functionName = function( req, res ) {
customFunctionThatRequiresReq( req );
};
最初的问题
我最近一直在玩node.js,并且有点担心它的全局范围。假设我们有一个 server.js 文件:
username = ""; //Global scope
然后,当连接建立并且服务器收到请求时,它将执行以下操作:
username = selectUsernameWithConditions(); //This will return a username
我的问题是:如果两台不同的计算机向服务器发送请求,
username
的值会独立不同吗?我的意思是,处理第一个请求时的 username
与处理第二个请求时的 username
是否不同,或者它们只是一个变量,将被覆盖?
如果它们被覆盖,存储数据并使它们仅在该请求和/或会话中全局访问的最佳方式是什么?例如下面的代码:
username = selectUsernameWithConditions(); //This will return a username
将为不同的请求分配不同的
username
并且不会相互覆盖。
是的,但有一些注意事项。
您正在寻找一个名为 continuation-local-storage 的模块。
这允许您为当前请求的其余回调保留任意数据,并以全局方式访问它。
我写了一篇关于它的博客文章here。但要点是这样的:
npm install --save continuation-local-storage
为您的应用程序创建一个命名空间(位于应用程序主文件的顶部)
var createNamespace = require('continuation-local-storage').createNamespace,
namespace = createNamespace('myAppNamespace');
创建一个在 cls(continuation-local-storage)命名空间中运行下游函数的中间件
var getNamespace = require('continuation-local-storage').getNamespace,
namespace = getNamespace('myAppNamespace'),
app.use(function(req, res, next) {
// wrap the events from request and response
namespace.bindEmitter(req);
namespace.bindEmitter(res);
// run following middleware in the scope of the namespace we created
namespace.run(function() {
namespace.set(‘foo’, 'a string data');
next();
});
});
自从您在
next
中运行 namespace.run
以来,任何下游函数都可以访问命名空间中的数据
var getNamespace = require('continuation-local-storage').getNamespace,
namespace = getNamespace('myAppNamespace');
// Some downstream function that doesn't have access to req...
function doSomething() {
var myData = namespace.get('foo');
// myData will be 'a string data'
}
需要注意的是,某些模块可能会“丢失”由 cls 创建的上下文。这意味着当您在名称空间上查找“foo”时,它不会找到它。有几种方法可以解决这个问题,即使用另一个模块,如 cls-redis、cls-q,或绑定到命名空间。
根据请求,我认为您所追求的可以通过普通的闭包来完成。例如,您可以在采用
req
参数的模块中定义自定义函数:
util_funcs.js:
module.exports = function( req ){
return {
customFunctionThatRequiresReq: function(){ console.info( req ) },
otherFunctionThatRequiresReq: function(){ console.log( req ) }
};
};
然后,无论您在哪里依赖这些函数(可能是应用程序中其他地方的一些中间件),您都可以在上下文中需要它们:
var someMiddleWare = function( req, res, next ){
var utils = require( 'util_funcs.js' )( req );
utils.customFunctionThatRequiresReq();
utils.otherFunctionThatRequiresReq();
};
这可以让您避免在函数参数中使用
req
,并且没有可疑的全局变量。
如果我正确理解你的问题,你可以尝试在节点js中创建可以存储用户名的全局变量
您可以使用具有唯一ID的全局数组
假设 user1 发起了 http 请求,因此你在 Node js 中像这样存储
if(!username)
username = [];
if(!uniqId)
uniqId = 0;
uniqId++;
username[uniqId] = 'xyz';
类似这样它正在工作
你可以使用不稳定的功能:nodejs domains
我在脑海中执行此操作,因此请阅读文档并弄清楚它是如何工作的;)
在层次结构的高层创建一个中间件,该中间件将创建一个域并在该域的上下文中运行其余的请求处理程序:
app.use(function(req, res, next) {
var domain = domain.create();
domain.req = req;
domain.run(next);
});
然后在处理程序中的任何位置,您都可以通过以下方式访问当前请求:
var req = process.domain.req;
再次阅读文档,我真的不确定这一切,但这是一种方法!
这个问题在这里得到了很好的回答在任何地方访问请求上下文:
Node 最近将此作为本机功能引入:AsyncLocalStorage 类似于其他语言中的线程本地存储。
您尝试过使用cookie吗? 将 cookie 设置到浏览器,然后每次有请求时,您都会通过 cookie 知道用户。 您可以使用“cookie-parser”节点库。