更多内容请访问 rubyonrails.org:

Rails on Rack

本指南涵盖了 Rails 与 Rack 的集成以及与其他 Rack 组件的接口。

阅读本指南后,您将了解

  • 如何在 Rails 应用程序中使用 Rack 中间件。
  • Action Pack 的内部中间件栈。
  • 如何定义自定义中间件栈。

本指南假设您对 Rack 协议和 Rack 概念(如中间件、URL 映射和 Rack::Builder)有基本了解。

1. Rack 简介

Rack 为使用 Ruby 开发 Web 应用程序提供了一个最小、模块化且适应性强的接口。通过以尽可能简单的方式封装 HTTP 请求和响应,它将 Web 服务器、Web 框架以及介于两者之间的软件(所谓的中间件)的 API 统一并提炼为一个方法调用。

解释 Rack 的工作原理不属于本指南的范围。如果您不熟悉 Rack 的基础知识,您应该查看下面的资源部分。

2. Rack 上的 Rails

2.1. Rails 应用程序的 Rack 对象

Rails.application 是 Rails 应用程序的主要 Rack 应用程序对象。任何符合 Rack 规范的 Web 服务器都应该使用 Rails.application 对象来提供 Rails 应用程序。

2.2. bin/rails server

bin/rails server 的基本工作是创建一个 Rack::Server 对象并启动 Web 服务器。

以下是 bin/rails server 如何创建 Rack::Server 实例的:

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

Rails::Server 继承自 Rack::Server,并以这种方式调用 Rack::Server#start 方法:

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

2.3. 开发和自动重载

中间件只加载一次,并且不监控更改。您需要重新启动服务器才能使更改反映在运行的应用程序中。

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 通过 application.rb 或特定环境的配置文件 environments/.rb,提供了一个简单的配置接口 config.middleware,用于添加、删除和修改中间件栈中的中间件。

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

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

  • 负责将会话存储在 Cookie 中。

ActionDispatch::Flash

ActionDispatch::ContentSecurityPolicy::Middleware

  • 提供一个 DSL 来配置 Content-Security-Policy 头。

Rack::Head

  • 对所有 HEAD 请求返回一个空主体。它保持所有其他请求不变。

Rack::ConditionalGet

  • 添加对“条件 GET”的支持,以便如果页面未更改,服务器不返回任何内容。

Rack::ETag

  • 在所有 String 主体上添加 ETag 头。ETag 用于验证缓存。

Rack::TempfileReaper

  • 清理用于缓冲多部分请求的临时文件。

您可以在自定义 Rack 栈中使用上述任何中间件。

4. 资源

4.1. 学习 Rack

4.2. 理解中间件



回到顶部