v7.1.3.2
更多資訊請見 rubyonrails.org: 更多 Ruby on Rails

Rails on Rack

本指南涵蓋 Rails 與 Rack 的整合,以及與其他 Rack 元件的介面。

閱讀本指南後,您將了解

本指南假設您具備 Rack 協定和 Rack 概念(例如中間件、URL 對應和 Rack::Builder)的基本知識。

1 Rack 簡介

Rack 提供一個極簡、模組化且可適應的介面,用於在 Ruby 中開發網路應用程式。它以最簡單的方式包裝 HTTP 要求和回應,將網路伺服器、網路架構和介於兩者之間的軟體(所謂的中間件)的 API 統一並精簡成單一方法呼叫。

說明 Rack 的運作方式並非本指南的範疇。如果您不熟悉 Rack 的基礎知識,您應該查看以下的 資源 區段。

2 Rails on Rack

2.1 Rails 應用程式的 Rack 物件

Rails.application 是 Rails 應用程式的主要 Rack 應用程式物件。任何符合 Rack 的網路伺服器都應該使用 Rails.application 物件來提供 Rails 應用程式。

2.2 bin/rails server

bin/rails server 執行建立 Rack::Server 物件和啟動網路伺服器的基本工作。

以下是 bin/rails server 建立 Rack::Server 執行個體的方式

Rails::Server.new.tap do |server|
  require APP_PATH
  Dir.chdir(Rails.application.root)
  server.start
end

Rails::ServerRack::Server 繼承,並以這種方式呼叫 Rack::Server#start 方法

class Server < ::Rack::Server
  def start
    # ...
    super
  end
end

2.3 rackup

若要使用 rackup 取代 Rails 的 bin/rails server,可以在 Rails 應用程式的根目錄的 config.ru 內放置下列內容

# Rails.root/config.ru
require_relative "config/environment"
run Rails.application

並啟動伺服器

$ rackup config.ru

若要進一步瞭解不同的 rackup 選項,可以執行

$ rackup --help

2.4 開發和自動重新載入

中介軟體載入一次,且不會監控變更。必須重新啟動伺服器,才會在執行中應用程式反映變更。

3 Action Dispatcher 中介軟體堆疊

Action Dispatcher 的許多內部元件都實作為 Rack 中介軟體。Rails::Application 使用 ActionDispatch::MiddlewareStack 來結合各種內部和外部中介軟體,以形成完整的 Rails Rack 應用程式。

ActionDispatch::MiddlewareStack 是 Rails 等同於 Rack::Builder 的元件,但建置為具備更好的彈性,以及更多功能以符合 Rails 的需求。

3.1 檢查中介軟體堆疊

Rails 有個方便的指令,可用於檢查正在使用的中介軟體堆疊

$ bin/rails middleware

對於新產生的 Rails 應用程式,可能會產生類似下列內容

use ActionDispatch::HostAuthorization
use Rack::Sendfile
use ActionDispatch::Static
use ActionDispatch::Executor
use ActionDispatch::ServerTiming
use ActiveSupport::Cache::Strategy::LocalCache::Middleware
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use ActionDispatch::RemoteIp
use Sprockets::Rails::QuietAssets
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use WebConsole::Middleware
use ActionDispatch::DebugExceptions
use ActionDispatch::ActionableExceptions
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ContentSecurityPolicy::Middleware
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Rack::TempfileReaper
run MyApp::Application.routes

這裡顯示的預設中介軟體(以及其他一些中介軟體)會分別在 內部中介軟體 區段中摘要說明。

3.2 設定中介軟體堆疊

Rails 提供一個簡單的組態介面 config.middleware 來透過 application.rb 或環境特定組態檔案 environments/<environment>.rb 來新增、移除和修改中間件堆疊中的中間件。

3.2.1 新增中間件

你可以使用下列方法在中間件堆疊中新增新的中間件

  • config.middleware.use(new_middleware, args) - 在中間件堆疊的底部新增新的中間件。

  • config.middleware.insert_before(existing_middleware, new_middleware, args) - 在中間件堆疊中指定現有的中間件之前新增新的中間件。

  • config.middleware.insert_after(existing_middleware, new_middleware, args) - 在中間件堆疊中指定現有的中間件之後新增新的中間件。

# config/application.rb

# Push Rack::BounceFavicon at the bottom
config.middleware.use Rack::BounceFavicon

# Add Lifo::Cache after ActionDispatch::Executor.
# Pass { page_cache: false } argument to Lifo::Cache.
config.middleware.insert_after ActionDispatch::Executor, Lifo::Cache, page_cache: false

3.2.2 交換中間件

你可以使用 config.middleware.swap 來交換中間件堆疊中現有的中間件。

# config/application.rb

# Replace ActionDispatch::ShowExceptions with Lifo::ShowExceptions
config.middleware.swap ActionDispatch::ShowExceptions, Lifo::ShowExceptions

3.2.3 移動中間件

你可以使用 config.middleware.move_beforeconfig.middleware.move_after 來移動中間件堆疊中現有的中間件。

# config/application.rb

# Move ActionDispatch::ShowExceptions to before Lifo::ShowExceptions
config.middleware.move_before Lifo::ShowExceptions, ActionDispatch::ShowExceptions
# config/application.rb

# Move ActionDispatch::ShowExceptions to after Lifo::ShowExceptions
config.middleware.move_after Lifo::ShowExceptions, ActionDispatch::ShowExceptions

3.2.4 刪除中間件

將下列程式碼新增至你的應用程式組態

# config/application.rb
config.middleware.delete Rack::Runtime

現在如果你檢查中間件堆疊,你會發現 Rack::Runtime 不再是其中的一部分。

$ bin/rails middleware
(in /Users/lifo/Rails/blog)
use ActionDispatch::Static
use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000001c304c8>
...
run Rails.application.routes

如果你想要移除與工作階段相關的中間件,請執行下列動作

# config/application.rb
config.middleware.delete ActionDispatch::Cookies
config.middleware.delete ActionDispatch::Session::CookieStore
config.middleware.delete ActionDispatch::Flash

而要移除與瀏覽器相關的中間件,

# config/application.rb
config.middleware.delete Rack::MethodOverride

如果你想要在你嘗試刪除不存在的項目時引發錯誤,請改用 delete!

# config/application.rb
config.middleware.delete! ActionDispatch::Executor

3.3 內部中間件堆疊

Action Controller 的許多功能都是以中間件實作的。下列清單說明了每個中間件的目的

ActionDispatch::HostAuthorization

  • 透過明確允許可以傳送請求的主機來防範 DNS 重新繫結攻擊。請參閱 組態指南 以取得組態說明。

Rack::Sendfile

ActionDispatch::Static

Rack::Lock

  • env["rack.multithread"] 標記設定為 false,並將應用程式包覆在 Mutex 中。

ActionDispatch::Executor

  • 用於在開發期間進行執行緒安全的程式碼重新載入。

ActionDispatch::ServerTiming

  • 設定 Server-Timing 標頭,其中包含請求的效能指標。

ActiveSupport::Cache::Strategy::LocalCache::Middleware

  • 用於記憶體快取。此快取並非執行緒安全。

Rack::Runtime

  • 設定 X-Runtime 標頭,其中包含執行請求所花費的時間(以秒為單位)。

Rack::MethodOverride

  • 如果設定 params[:_method],則允許覆寫方法。這是支援 PUT 和 DELETE HTTP 方法類型的中間件。

ActionDispatch::RequestId

  • 提供一個獨特的 X-Request-Id 標頭供回應使用,並啟用 ActionDispatch::Request#request_id 方法。

ActionDispatch::RemoteIp

  • 檢查 IP 欺騙攻擊。

Sprockets::Rails::QuietAssets

  • 抑制資產請求的記錄器輸出。

Rails::Rack::Logger

  • 通知記錄請求已開始。請求完成後,清除所有記錄。

ActionDispatch::ShowExceptions

  • 救援應用程式傳回的任何例外,並呼叫例外應用程式,該應用程式會將其包覆成適合最終使用者閱讀的格式。

ActionDispatch::DebugExceptions

  • 負責記錄例外,並在請求為本機時顯示偵錯頁面。

ActionDispatch::ActionableExceptions

  • 提供從 Rails 錯誤頁面派送動作的方法。

ActionDispatch::Reloader

  • 提供準備和清理回呼,旨在協助開發期間的程式碼重新載入。

ActionDispatch::Callbacks

  • 提供在請求調度前後執行的回呼。

ActiveRecord::Migration::CheckPending

  • 檢查待處理的遷移,如果任何遷移待處理,則引發 ActiveRecord::PendingMigrationError

ActionDispatch::Cookies

  • 設定請求的 Cookie。

ActionDispatch::Session::CookieStore

  • 負責將 Session 儲存在 Cookie 中。

ActionDispatch::Flash

ActionDispatch::ContentSecurityPolicy::Middleware

  • 提供一個 DSL 來設定 Content-Security-Policy 標頭。

Rack::Head

  • 傳回所有 HEAD 請求的空主體。它讓所有其他請求保持不變。

Rack::ConditionalGet

  • 新增對「條件式 GET」的支援,以便在頁面未變更時,伺服器不回應任何內容。

Rack::ETag

  • 在所有字串主體上新增 ETag 標頭。ETag 用於驗證快取。

Rack::TempfileReaper

  • 清除用於緩衝多部分請求的暫存檔案。

可以在自訂的 Rack 堆疊中使用上述任何中間件。

4 項資源

4.1 學習 Rack

4.2 了解中間件

回饋

鼓勵您協助提升本指南的品質。

如果您發現任何錯字或事實錯誤,請協助我們修正。若要開始,您可以閱讀我們的 文件貢獻 部分。

您也可能會發現不完整的內容或未更新的內容。請務必新增任何遺漏的主要文件。請務必先查看 Edge Guides,以驗證問題是否已在主分支中修正。查看 Ruby on Rails 指南準則 以了解樣式和慣例。

如果您發現需要修正的地方,但無法自行修補,請 開啟問題

最後但同樣重要的是,任何有關 Ruby on Rails 文件的討論都非常歡迎在 官方 Ruby on Rails 論壇 上進行。