本指南假设您对 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_before
和 config.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
- 设置特定于服务器的 X-Sendfile 标头。通过
config.action_dispatch.x_sendfile_header
选项进行配置。
ActionDispatch::Static
- 用于从 public 目录提供静态文件服务。如果
config.public_file_server.enabled
为false
,则禁用。
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
- 设置闪存键。只有在
config.session_store
设置为某个值时才可用。
ActionDispatch::ContentSecurityPolicy::Middleware
- 提供一个 DSL 用于配置 Content-Security-Policy 头。
Rack::Head
- 对于所有 HEAD 请求返回一个空主体。它保留所有其他请求不变。
Rack::ConditionalGet
- 添加对“条件
GET
”的支持,以便服务器在页面未更改时返回空内容。
Rack::ETag
- 在所有字符串主体上添加 ETag 标头。ETags 用于验证缓存。
Rack::TempfileReaper
- 清理用于缓冲多部分请求的临时文件。
您可以在自定义 Rack 堆栈中使用上述任何中间件。