node.js是否会在连接之间共享数据的风险更大?

由于node.js是单线程的,并且许多请求使用asynchronouscallback或事件并行运行,并且任何一个请求都不会立即运行到完成状态,所以从一个http请求的进程最终会与其他请求共享variables当将数据存储在函数/模块中的临时对象或variables中时?

例如,在PHP中,每个进程得到它自己的线程,并运行到完成(阻止其他任何东西)。 因此,无法通过连接/请求访问variables。

我试图谷歌search,但没有发现太多。 这甚至是一个问题吗? 是否有可能在不同的(甚至是相同的)用户的个别请求之间无意中共享variables?

只有一种情况,这可能是一个问题:无意的全局variables。

考虑以下快速路线:

app.post('/foo', function(req, res) { var user = req.cookies.user; token = generateToken(user); someAsyncOperation(user, req.body, function(err, result) { saveUser(token, result); res.send(result); }); }); 

你看到错误吗? user的范围是该函数的范围,但token是一个隐式的全局variables,将在所有请求之间共享。

在这个例子中,可能假设的作者意图在user定义之后使用逗号(而不是分号)(这会导致token被正确地限定范围)。 不幸的是,他的手指向东北方向下降了一厘米,并创造了一个容易错过的错误。

  • 请求A进来, user从cookie加载,并且某种types的令牌生成函数创build应该对用户唯一的令牌。
  • 一个asynchronous操作被排队,并且callback函数被绑定到请求范围A.
  • asynchronous操作需要一些时间,所以节点空闲。
  • 请求B进来。它在其范围内初始化一个新user
  • 全局token被请求B的令牌覆盖
  • 另一个asynchronous操作排队等待B; 节点再次空闲。
  • A的asynchronous操作完成。
  • 嗯,哦。 A的操作结果是使用B的标记保存的,因为这是最后设置的token
  • B的asynchronous操作完成并将更多的数据保存到B的令牌中。

在这种情况下,没有任何东西被保存到A中,并且两组数据被保存到B.这可能导致一些奇怪的不一致,几乎不可能重现和debugging,直到实际的经济损失。 (我是不是意外地发了两份订单?)

好消息是很容易避免这个问题。 使用严格的模式 。 严格模式使除了其他事情之外,对隐式全局variables赋值ReferenceError 。 只需添加到您的js文件的顶部:

 'use strict'; 

或者用参数运行节点:

 --use_strict 

严格的模式,你不能意外地使用一个隐式的全局,所以这不再是一个问题。 局部variables和req / res对象是安全的; 你可能遇到麻烦的唯一的另一个领域就是你有意使用某种共享状态,但是其他语言的危害是相同的。

Javascript的工作方式不同于PHP。 范围的行为是完全不同的,是防止问题成为问题的原因。

现实世界的比喻是想象你有许多工作台。 你的老板进来,把一些物品放在一张长凳上去做。 当你正在做这件事的时候,他把更多的东西放在其他的长凳上。

在某个时刻,您到达第一个办公桌的停车点,您将不得不等待。 你转到2号台开始在那里工作。 一旦你看到第一张桌子再次准备好了,你就去第一张桌子,继续工作。 既然你有完全不同的办公桌,很难混起来。 你只需要记住不要带东西。 Node中的每个函数都有完全不同的范围,这使得节点很难混淆正在做的事情。

 function object_init() { this.a = 'a'; return this } function server_resp(req, res) { var obj = object_init(); if ( req.changeTrue() ) { obj.a = 'b'; } function test() { longOperation(); console.log( obj.a ); } test() } 

上面的代码片段是Node.js应用程序在很高层次上可能发生的一些正常的片段。 大多数JavaScript应用程序将有一个非常类似于这个代码片段。

你关心的是,在longOperation()之后Node将返回到server_resp的错误实例。 之所以没有发生是因为每个请求都有自己的“板凳”。 节点足够聪明,可以从一个工作台移动到另一个工作台,而不需要将物品从一个搬到另一个。 节点的工作是执行不执行。 每个“板凳”都有自己的目标。 每个“板凳”甚至有自己的testing()。 这是Javascript工作的方式,因为函数与对象关系非常密切。

PHP有一个完全不同的内存和执行模式比JavaScript,这就是为什么JavaScript可以做到这一点安全。 PHP是更程序化/面向对象,而JavaScript有更多的function味道。

这是节点如何工作的一般解释。 潜藏在表面之下可能存在安全漏洞。 根据内存模型和大小检查,整数溢出可以重写内存库,并让攻击者访问他们以前没有访问的范围。 糟糕的代码可能会扩大这个漏洞。 对于普通代码,不同请求之间的混合将几乎不可能实现。

如果你做得对,这并不是一个真正的问题,我并不是说这就是轻浮。 :-)大多数语言具有全局范围或共享/可共享的数据结构。 即使使用线程操作,这也是一个风险,例如在线程环境中不恰当地使用/实现Singleton。 如果花一些时间来理解Javascript是如何工作的,并且以反映这种理解的方式编写代码,这确实不应该是一个问题。

我build议你可以不要在search结果中对它进行大量的讨论,因为在networking上有很多关于javascript的东西,应该让你放心,这不是一个大问题。

花一些时间来了解(通过阅读和一些实验)关于范围和封闭如何在Javascript中工作,你应该对此感到更加舒适。

关于这个问题的前两个评级答案应该有助于理解范围和closures。 除此之外,请查看构build在Express上的各种示例应用程序(并深入了解Express和Connect的代码),并了解它们是如何实现的。