学习目标:理解 ActionPack 的整体架构和请求处理流程
引言#
ActionPack 是 Rails 的 MVC 中的 C(Controller)和 V(View)层,负责处理 HTTP 请求和生成响应。
1. ActionPack 的组成#
1.1 核心组件#
ActionPack
├── ActionDispatch # 路由和中间件
├── ActionController # 控制器
└── AbstractController # 抽象控制器基类
1.2 与 Rack 的关系#
# Rails 应用是一个 Rack 应用
Rails.application.is_a?(Rack::Application) # => true
# config.ru
run Rails.application
2. Rack 接口#
2.1 Rack 应用的本质#
# 最简单的 Rack 应用
class HelloApp
def call(env)
[200, {"Content-Type" => "text/plain"}, ["Hello World"]]
end
end
# Rack 应用必须响应 call 方法
# 接收环境哈希
# 返回 [状态码, 响应头, 响应体]
2.2 Rails 如何实现 Rack#
# railties/lib/rails/application.rb
module Rails
class Application < Engine
def call(env)
env["action_dispatch.request_id"] = SecureRandom.uuid
@middleware_stack.call(env)
end
end
end
3. 中间件栈#
3.1 什么是中间件?#
class SimpleMiddleware
def initialize(app)
@app = app
end
def call(env)
# 请求前处理
puts "Before request"
status, headers, body = @app.call(env)
# 响应后处理
puts "After request"
[status, headers, body]
end
end
3.2 Rails 的中间件栈#
$ rails middleware
use Rack::Sendfile
use ActionDispatch::Static
use Rack::Runtime
use ActionDispatch::RequestId
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
run MyApp::Application.routes
3.3 自定义中间件#
# config/application.rb
config.middleware.use MyMiddleware
config.middleware.insert_before Rack::Runtime, MyMiddleware
config.middleware.delete Rack::Runtime
4. 请求生命周期#
4.1 完整的请求流程#
1. 浏览器发送 HTTP 请求
↓
2. Web 服务器(Puma)接收请求
↓
3. Rack 接口转换为 env 哈希
↓
4. 经过中间件栈处理
↓
5. 路由匹配(ActionDispatch::Routing)
↓
6. 分发到控制器(ActionController)
↓
7. 执行 action
↓
8. 渲染视图(ActionView)
↓
9. 返回响应
↓
10. 反向经过中间件栈
↓
11. 发送给浏览器
4.2 Request 和 Response 对象#
# ActionDispatch::Request
request.path # => "/users/1"
request.method # => "GET"
request.params # => {"id" => "1"}
request.headers # => {"Accept" => "text/html", ...}
request.cookies # => {"session_id" => "..."}
request.xhr? # => false (是否 AJAX)
request.remote_ip # => "192.168.1.1"
# ActionDispatch::Response
response.status # => 200
response.headers # => {"Content-Type" => "text/html", ...}
response.body # => "<html>...</html>"
response.content_type # => "text/html"
5. ActionDispatch 核心类#
5.1 RouteSet - 路由集合#
# actionpack/lib/action_dispatch/routing/route_set.rb
class RouteSet
def draw(&block)
# 执行 config/routes.rb 中的代码
end
def recognize_path(path, environment = {})
# 识别路径,返回控制器和 action
end
end
5.2 Journey - 路由引擎#
# Rails 使用 Journey 库进行路由匹配
# actionpack/lib/action_dispatch/journey/
6. 参数处理#
6.1 参数的来源#
# URL 参数
# GET /users?name=John
params[:name] # => "John"
# 路径参数
# GET /users/1
# routes: get '/users/:id', to: 'users#show'
params[:id] # => "1"
# POST 数据
# POST /users
# Body: { user: { name: "John" } }
params[:user][:name] # => "John"
6.2 Strong Parameters#
class UsersController < ApplicationController
def create
@user = User.new(user_params)
# ...
end
private
def user_params
params.require(:user).permit(:name, :email, :password)
end
end
# 不允许的参数会被过滤
# params = { user: { name: "John", admin: true } }
# user_params => { name: "John" } # admin 被过滤
7. Session 和 Cookies#
7.1 Session#
# 存储在 session 中
session[:user_id] = current_user.id
# 读取
current_user_id = session[:user_id]
# 删除
session.delete(:user_id)
# 清空
reset_session
7.2 Cookies#
# 普通 cookie
cookies[:user_preference] = "dark_mode"
# 签名 cookie(防止篡改)
cookies.signed[:user_id] = current_user.id
# 加密 cookie
cookies.encrypted[:secret_data] = "sensitive"
# 永久 cookie
cookies.permanent[:remember_token] = token
8. Flash 消息#
class SessionsController < ApplicationController
def create
if user.authenticate(params[:password])
flash[:success] = "Welcome back!"
redirect_to root_path
else
flash.now[:error] = "Invalid credentials"
render :new
end
end
end
# 视图中
<% if flash[:success] %>
<div class="alert alert-success"><%= flash[:success] %></div>
<% end %>
9. 本章总结#
ActionPack 是 Rails 请求处理的核心:
- 基于 Rack 接口
- 使用中间件栈处理请求
- 提供路由、控制器、视图支持
- 处理参数、会话、cookies
上一篇:ActiveModel 接口 下一篇:路由系统深入 返回:学习指南首页