本指南假设您对 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/,提供了一个简单的配置接口 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_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
- 用于从公共目录提供静态文件。如果
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
- 设置 Flash 键。仅当
config.session_store设置了值时才可用。
ActionDispatch::ContentSecurityPolicy::Middleware
- 提供一个 DSL 来配置 Content-Security-Policy 头。
Rack::Head
- 对所有 HEAD 请求返回一个空主体。它保持所有其他请求不变。
Rack::ConditionalGet
- 添加对“条件
GET”的支持,以便如果页面未更改,服务器不返回任何内容。
Rack::ETag
- 在所有 String 主体上添加 ETag 头。ETag 用于验证缓存。
Rack::TempfileReaper
- 清理用于缓冲多部分请求的临时文件。
您可以在自定义 Rack 栈中使用上述任何中间件。