在Sinatra请求之间共享Ruby变量

Ves*_*iev 4 html ruby rest sinatra web

我正在尝试在sinatra中编写一个简单的问答游戏,我需要为所有用户提供可访问的公共对象(大厅状态,聊天消息等).问题是Sinatra在每个请求和对象变为初始状态后重新加载代码.怎么实现呢?

mde*_*tis 10

好吧,这个话题有点棘手.Sinatra实际上没有重置服务器状态:

require 'sinatra'

GlobalState = {}
GlobalState[:some_counter] = 0

get '/' do
  response = "GlobalState[:some_counter]: #{GlobalState[:some_counter]}"
  GlobalState[:some_counter] += 1
  response
end
Run Code Online (Sandbox Code Playgroud)

这段代码没有错:如果你运行它并转到http://localhost:4567你会看到GlobalState[:some_counter]增加预期.

由于以下原因而不鼓励,主要与应用程序的Web性质有关:

  1. 由于数据存储在Ruby对象中,因此如果停止服务器,则会丢失数据.但是,如果您不需要持久数据,那么这不是问题
  2. 当您运行Web应用程序时,通常您会同时拥有应用程序实例,以便同时处理多个请求.有几种方法可以实现它:
    1. Forks:同一应用程序的多个进程.它们不共享内存,因此Ruby全局状态变量变得无用
    2. 线程:线程共享内存,因此您可以访问全局状态,但是您必须管理对同一个全局对象的并发访问,并带来非常重要的后果
  3. 您无法将数据与用户关联,反之亦然:这是因为HTTP不提供状态保留方法(它是无状态协议).要解决它,您需要:
    1. 客户端数据存储:cookies,HTML5本地存储......
    2. 服务器端数据存储:会话(不是真正的服务器端,你至少需要会话各自的客户联系起来,通常存储会话ID添加到饼干)

出于这些原因,Web应用程序数据管理并非易事.无论如何不要担心,你不必重新发明轮子; 解决方案在手: