文档目录
中间件执行流程

简介

本文面向 DouPHP 框架的“中间件执行流程”,聚焦请求进入、中间件管道执行、响应返回的全生命周期。重点说明:

  • 中间件的执行顺序控制、条件执行机制、短路执行模式
  • 上下文对象在中间件间的传递与共享方式
  • 不同路由类型(前台、后台、API)的中间件差异
  • 执行流程图与时序图,帮助理解请求处理的生命周期
  • 性能监控、执行时间统计与调试建议

项目结构

DouPHP 将中间件按端(前台 Front、后台 Admin、API)组织,并通过统一的调度器 Dispatcher 将匹配到的路由计划交由 MiddlewarePipeline 执行。安全头、鉴权、限流等横切关注点以中间件形式挂载到管道中。

graph TB
subgraph "调度层"
D["Dispatcher<br/>分发器"]
end
subgraph "中间件管道"
P["MiddlewarePipeline<br/>管道"]
M1["安全头中间件<br/>AbstractSecurityHeadersMiddleware"]
M2["认证中间件<br/>Admin/Front/API"]
M3["权限/限流/CSRF<br/>各端中间件"]
end
subgraph "控制器"
C["控制器方法<br/>业务逻辑"]
end
D --> P
P --> M1
M1 --> M2
M2 --> M3
M3 --> C

核心组件

  • 中央分发器 Dispatcher:负责注入路由参数、构建并运行中间件管道,最终调用控制器方法。
  • 路由条目 RouteEntry:承载路由元信息,包括是否跳过全部中间件、路由级中间件参数等。
  • 安全头基类 AbstractSecurityHeadersMiddleware:在管道最前置下发安全响应头,仅对命中路由生效。
  • 可参数化中间件接口 ParameterizedMiddleware:支持路由级参数覆盖,为每个路由创建独立实例并注入参数。
  • 各端中间件:
    • 后台 AuthMiddleware:恢复管理员登录态,未登录抛异常跳转登录页。
    • 前台 UserAuthMiddleware:基于 Session 解析用户登录态,拒绝时重定向或返回 JSON。
    • API UserAuthMiddleware:从 Authorization 头提取 token,解析用户上下文,拒绝时返回 JSON 错误。

架构总览

请求进入后,Dispatcher 将路由参数注入 Request,然后构造中间件管道。管道依次执行安全头、认证、权限/限流等中间件;任一中间件短路返回响应,后续中间件不再执行。若通过所有中间件,则实例化控制器并调用目标方法,返回值作为响应继续回传。

sequenceDiagram
participant Client as "客户端"
participant Router as "端路由器"
participant Disp as "Dispatcher"
participant Pipe as "MiddlewarePipeline"
participant MW1 as "安全头中间件"
participant MW2 as "认证中间件"
participant Ctrl as "控制器"
Client->>Router : HTTP 请求
Router-->>Disp : 分发计划(含中间件列表)
Disp->>Disp : 注入路由参数到 Request
Disp->>Pipe : 构建并运行管道
Pipe->>MW1 : handle(next)
MW1->>MW1 : 下发安全响应头
MW1->>Pipe : next()
Pipe->>MW2 : handle(next)
alt 认证失败
MW2-->>Pipe : 短路返回响应(JSON/重定向)
Pipe-->>Client : 响应
else 认证成功
MW2->>Pipe : next()
Pipe->>Ctrl : 调用控制器方法
Ctrl-->>Pipe : 返回响应
Pipe-->>Client : 响应
end

详细组件分析

分发器与管道执行

  • Dispatcher 在管道前将路由参数写入 Request,确保中间件和控制器均可读取路径段参数。
  • 使用 MiddlewarePipeline::make($plan->middlewares)->run(...) 包裹控制器调用,形成“洋葱模型”式执行链。
  • 若计划标记为未找到(isNotFound),直接返回 null,由端路由器渲染专属 404。
flowchart TD
Start(["进入 Dispatcher.run"]) --> Check{"是否未匹配?"}
Check --> |是| ReturnNull["返回 null<br/>交由端路由渲染404"]
Check --> |否| Inject["注入路由参数到 Request"]
Inject --> BuildPipe["构建中间件管道"]
BuildPipe --> RunPipe["运行管道并调用控制器"]
RunPipe --> End(["返回响应"])

路由级中间件配置与短路

  • RouteEntry 支持 skip_all_middleware 标志位,用于跳过该路由的全部中间件。
  • 路由可声明 middleware_params,配合 ParameterizedMiddleware 实现参数化中间件(如 Throttle 次数/窗口、Permission 节点)。
  • 中间件可在 handle 中提前返回响应,实现短路(例如认证失败、限流触发)。
flowchart TD
A["路由声明"] --> B{"skip_all_middleware ?"}
B --> |是| C["跳过全部中间件"]
B --> |否| D["加载中间件列表"]
D --> E{"是否存在路由级参数?"}
E --> |是| F["为参数化中间件新建实例并注入参数"]
E --> |否| G["使用默认实例"]
F --> H["执行管道"]
G --> H
H --> I{"中间件短路?"}
I --> |是| J["返回响应"]
I --> |否| K["继续下一个中间件"]

安全头中间件(全局前置)

  • AbstractSecurityHeadersMiddleware 在管道最前置下发安全响应头(X-Content-Type-Options、X-Frame-Options、Referrer-Policy、Permissions-Policy),HSTS 仅在 HTTPS 且配置开启时下发。
  • 仅对已匹配路由生效;404 由 Router 自渲染,不在覆盖范围内。
  • 前台薄壳 SecurityHeadersMiddleware 继承基类,行为一致。
classDiagram
class AbstractSecurityHeadersMiddleware {
+handle(next) mixed
-sendHeaders(headers) void
}
class SecurityHeadersMiddleware_Front {
}
AbstractSecurityHeadersMiddleware <|-- SecurityHeadersMiddleware_Front

认证中间件(三端差异)

  • 后台 AuthMiddleware:从 Session 恢复管理员登录态,未登录抛出 HttpResponseException 跳转登录页。
  • 前台 UserAuthMiddleware:基于 auth('front') 解析登录态;XHR 请求 from=js 时返回 JSON 401 并附带跳转地址;否则重定向到登录页。
  • API UserAuthMiddleware:从 Authorization: Bearer 提取 token,解析用户上下文;拒绝时返回 JSON 401/403。
sequenceDiagram
participant MW as "认证中间件"
participant Guard as "Guard(auth)"
participant Resp as "响应"
MW->>Guard : 解析登录态/上下文
alt 未认证
MW-->>Resp : 返回401/重定向
else 已认证
MW->>Guard : 注入身份缓存
MW-->>Resp : 放行next()
end

条件执行机制(模块级鉴权模式)

  • 前台与 API 均提供 init/middleware.php 配置文件,定义 auth_modes 与 work_required。
  • 规则键支持 module / module/action / module/sub / module/sub/action,值 public/optional/required,work_required 为 required 的子策略,额外校验工作端身份。
  • 新增模块需显式登记,避免静默以匿名形态上线。
flowchart TD
R["当前路由段"] --> L["匹配 auth_modes 规则"]
L --> M{"模式? public/optional/required"}
M --> |public| P["不尝试解析登录态"]
M --> |optional| O["尝试解析登录态, 失败不拦截"]
M --> |required| Q["必须登录"]
Q --> W{"是否命中 work_required?"}
W --> |是| W1["额外校验工作端身份"]
W --> |否| N["放行"]
O --> N
P --> N

上下文对象的传递与共享

  • 路由参数:Dispatcher 在管道前注入 Request,中间件与控制器均可通过 Request::route() 获取。
  • 用户身份:认证中间件通过 Guard 解析并 hydrate 身份缓存,后续中间件与控制器可通过 auth('front'|'api'|'admin') 访问。
  • 工作端身份:work_required 命中时,中间件会额外校验工作端身份,并在上下文中注入相关标识。

依赖关系分析

  • Dispatcher 依赖 MiddlewarePipeline 与 Container,负责组装与执行。
  • 各端中间件依赖各自 Guard(auth('front'|'api'|'admin'))与响应工具(ApiResponse、HttpResponseException)。
  • 安全头中间件依赖配置中心 Config,读取 security.headers。
  • 路由条目 RouteEntry 提供 skip_all_middleware 与 middleware_params,影响管道装配与参数注入。
graph LR
Dispatcher --> Pipeline["MiddlewarePipeline"]
Dispatcher --> Container["Container"]
Pipeline --> MW_Sec["安全头中间件"]
Pipeline --> MW_Auth["认证中间件"]
MW_Auth --> Guard["Guard(auth)"]
MW_Sec --> Config["Config"]
RouteEntry --> Pipeline

性能与监控

  • 执行时间统计:建议在管道外层(Dispatcher 或端路由入口)记录开始时间,在控制器返回后计算耗时,便于定位慢请求。
  • 中间件粒度日志:在每个中间件的 handle 前后记录日志,结合请求 ID 追踪链路。
  • 短路优化:将高开销但可能短路的中间件(如认证、限流)置于靠前位置,减少不必要的后续处理。
  • 路由级参数化:对限流、权限等中间件使用路由级参数,避免全局配置带来的误伤。
  • 安全头最小化:仅在命中路由下发安全头,避免对静态资源或非命中路径造成额外开销。

故障排查指南

  • 未命中路由:若计划标记为未找到,Dispatcher 返回 null,由端路由渲染 404;检查路由声明与匹配逻辑。
  • 认证失败:
    • 后台:抛出 HttpResponseException 跳转登录页,检查 Session 与 IP 绑定。
    • 前台:XHR 请求 from=js 返回 JSON 401 并带 jump_url;普通请求重定向到登录页。
    • API:返回 JSON 401/403,检查 Authorization 头与 token 有效性。
  • 限流触发:确认 ThrottleMiddleware 的路由级参数(次数/窗口)是否合理。
  • 安全头未下发:检查 headers_sent() 状态与 security.headers 配置。

结论

DouPHP 的中间件体系以 Dispatcher 为核心,结合 MiddlewarePipeline 形成清晰的请求处理流水线。安全头、认证、权限/限流等横切关注点通过中间件解耦,支持路由级参数化与条件执行。三端中间件在认证来源与响应格式上各有侧重,但整体执行模型一致。通过合理的中间件顺序、参数化配置与监控手段,可实现高效、可控的请求处理流程。

附录

  • 关键概念速查:
    • 中间件管道:洋葱模型,next() 控制流向,短路即返回响应。
    • 路由级参数:通过 ParameterizedMiddleware 注入,避免污染共享实例。
    • 条件执行:auth_modes 与 work_required 决定认证与工作端校验策略。
    • 上下文共享:Request::route() 提供路由参数,auth() 提供用户与工作端身份。
添加日期:2026-10-05