我正在尝试在 sinatra 中编写一个简单的问答游戏,我需要让所有用户都可以访问公共(public)对象(大厅状态、聊天消息等)。问题在于 Sinatra 在每个请求和对象都处于初始状态后重新加载代码。如何实现?
最佳答案
嗯,这个话题有点棘手。 Sinatra 实际上并没有重置服务器状态:
require 'sinatra'
GlobalState = {}
GlobalState[:some_counter] = 0
get '/' do
response = "GlobalState[:some_counter]: #{GlobalState[:some_counter]}"
GlobalState[:some_counter] += 1
response
end
这段代码没有任何问题:如果您运行它并转到 http://localhost:4567
,您将看到 GlobalState[:some_counter]
按预期递增。
但是由于以下原因不鼓励这样做,这些原因主要与应用程序的网络性质有关:
- 由于数据存储在 Ruby 对象中,如果您停止服务器,就会丢失数据。但是,如果您不需要持久数据,这不是问题
- 当您运行网络应用时,通常您会同时拥有多个应用实例,以便同时处理多个请求。有几种方法可以实现它:
- fork :同一应用程序的多个进程。它们不共享内存,因此 Ruby 全局状态变量变得无用
- 线程:线程共享内存,因此您可以访问全局状态,但您必须管理对同一个全局对象的并发访问,这会带来不小的后果
- 您不能将数据关联到用户,反之亦然:这是因为 HTTP 不提供状态保存方法(它是 stateless protocol )。为了解决它,您需要:
- 客户端数据存储:cookies、HTML5 Local Storage...
- 服务器端数据存储: session (不是真正的服务器端仅,您至少需要将 session 关联到各个客户端,通常将 session ID 存储到 cookie 中)
由于这些原因,网络应用数据管理并非易事。无论如何不用担心,您不必重新发明轮子;解决方案就在手边:
- Sinatra cookies 用于客户端数据存储
- 用于客户端-服务器数据共享的 Sinatra sessions
- 用于数据持久化的数据库
关于html - 在 Sinatra 请求之间共享 Ruby 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21945101/