Rails中的Thread.current 用法的安全性

对于将信息存储在Thread.current散列(例如,current_user,当前子域等等)中的做法,我总是有相互矛盾的观点。 该技术已被提出作为简化模型层(查询范围,审计等)内的后续处理的一种方式。

  • http://m.onkey.org/thread-safety-for-your-rails
  • http://rails-bestpractices.com/posts/47-fetch-current-user-in-models
  • 为什么我的线程variables在Rails中间歇性的?
  • 替代在Rails的API包装中使用Thread.current
  • Thread.current []值和类级别属性是否安全在rails中使用?

许多人认为这种做法是不可接受的,因为它打破了MVC模式。 其他人则对这种方法的可靠性/安全性表示担忧,我的两部分问题集中在后一方面。

  1. 是否保证Thread.current散列在其整个周期中只有一个响应是私有的?

  2. 我明白,一个线程,在响应结束时,可能会被移交给其他传入的请求,从而泄漏存储在Thread.current任何信息。 在响应结束之前清除这些信息(例如,通过从控制器的after_filter执行Thread.current[:user] = nil )是否足以防止这种安全漏洞?

谢谢! 朱塞佩

没有特别的理由远离线程局部variables,主要问题是:

  • testing它们就更困难了,因为在testing使用它的代码时,您必须记住设置线程局部variables
  • 使用线程局部variables的类将需要这些对象不可用的知识,但是在线程局部variables内部,这种间接性通常违反了demeter
  • 不清理线程本地可能是一个问题,如果你的框架重用线程(线程局部variables已经启动和代码依赖|| =调用来初始化variables可能会失败

所以,虽然使用并不是完全没有问题,但最好的方法是不要使用它们,但是有时候你会碰到一个局部线程将是最简单的解决scheme,而不会改变很多代码和你将不得不妥协,有一个不完美的面向对象的模型与本地线程或改变了相当多的代码来做同样的事情。

所以,这主要是一个思考的问题,这将成为您的案例的最佳解决scheme,如果你真的走下了线程本地的道路,我一定会build议你用记得清理后的块他们完成了,如下所示:

 around_filter :do_with_current_user def do_with_current_user Thread.current[:current_user] = self.current_user begin yield ensure Thread.current[:current_user] = nil end end 

这确保线程局部variables在使用之前被清理,如果这个线程被回收。

这个小gem确保您的线程/请求本地variables之间不要请求: https : //github.com/steveklabnik/request_store

接受的答案在技术上是准确的,但正如答案中所指出的那样,在http://m.onkey.org/thread-safety-for-your-rails中也不那么温和:;

不要使用线程本地存储, Thread.current如果你不是绝对必须的

request_store的gem是另一个解决scheme(更好),但只读readme有更多的原因远离线程本地存储。

几乎总是有一个更好的方法。