2014-02-21 66 views
4

我想在sinatra中編寫一個簡單的問答遊戲,我需要爲所有用戶(大堂狀態,聊天消息等)提供可訪問的公共對象。問題是Sinatra在每次請求和對象變爲初始狀態後重新加載代碼。任何人都可以給我一個建議如何實現它?在Sinatra請求之間共享Ruby變量

+2

在Web服務的發展,一個一般應努力使用進程間持久性機制(如數據庫,共享緩存)。Sinatra不會爲每個請求「重新加載代碼」,但它會創建新的對象 - 這將會有新的實例變量。如果使用全局/共享類變量或對象來維護狀態,則可能有*限制*「成功」,但這不是* * *是Web服務的首選機制,因爲它在進程重新啓動時很容易丟失數據,並且不會傳播多個前端進程之間的信息。 – user2864740

+0

感謝您的快速回復。看來我需要設置一個數據庫。 –

回答

8

那麼,這個話題有點棘手。西納特拉其實並不重置服務器狀態:

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]增加預期。

它不鼓勵出於以下原因,這主要涉及到應用程序的Web性質:

  1. 由於數據被存儲在一個Ruby對象,如果停止服務器,你鬆數據。但是,如果您不需要持久數據,這不是問題
  2. 當您運行Web應用程序時,通常您的應用程序同時存在實例,以便同時處理多個請求。有幾種方法可以實現它:
    1. 叉:同一應用程序的多個進程。它們不共享內存,所以Ruby全局狀態變量變得無用
    2. 線程:線程共享內存,因此您可以訪問全局狀態,但是您必須管理對同一全局對象的併發訪問,並且具有不重要的後果
  3. 無法將數據關聯到用戶,反之亦然:這是因爲HTTP不提供用於狀態保留的方法(它是stateless protocol)。爲了解決這個問題,你需要兩種:
    1. 客戶端數據存儲:餅乾,HTML5本地存儲...
    2. 服務器端數據存儲:會話(不是真正的服務器端,你需要至少到會話關聯到各個客戶端,通常存儲會話ID添加到餅乾)

出於這些原因,網絡應用程序數據管理是不平凡的。無論如何,不​​要擔心,你不必重新發明輪子;該解決方案在手:

0

如果沒有某種類型的持久存儲,沒有辦法做到這一點。您必須將信息存儲在數據庫或cookie中。