更多内容请访问 rubyonrails.org:

Rails 在 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 Rails 在 Rack 上

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 提供了一个简单的配置接口 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

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

ActionDispatch::Flash

ActionDispatch::ContentSecurityPolicy::Middleware

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

Rack::Head

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

Rack::ConditionalGet

  • 添加对“条件 GET”的支持,以便服务器在页面未更改时返回空内容。

Rack::ETag

  • 在所有字符串主体上添加 ETag 标头。ETags 用于验证缓存。

Rack::TempfileReaper

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

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

4 资源

4.1 学习 Rack

4.2 了解中间件



返回顶部