Swoft2 开源框架中的过滤器实现
- 作者: 刘杰
- 来源: 技术那些事
- 阅读:241
- 发布: 2025-06-22 23:21
- 最后更新: 2025-08-02 16:41
概述
针对请求响应式(request/response)服务,常见的设计巧妙的代码结构。
MiddleWare 相当于 Java Spring 程序中常用的过滤器,过滤器将 Servlet 层层包裹,用来处理 Request(Servlet 进行业务处理前请求)或者 Response(Servlet 进行业务处理后的响应)对象。此处示例代码中,defaultMiddleWare相当于对应的 Servlet 进行处理的最后一个过滤器。
设计
类图
%%{
init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#ff8c1f',
'primaryTextColor': 'black'
}
}
}%%
classDiagram
direction TB
class Request
class Response
class MiddleWareInterface {
<<interface>>
+ Response process(Request, RequestHandler)
}
class RequestHandler {
- MiddleWareInterface[] middleWares;
+ Response handle(Request);
}
UserMiddleWare --|> MiddleWareInterface
DefaultMiddleWare --|> MiddleWareInterface
RequestHandler o--> MiddleWareInterface
RequestHandler --> Request
RequestHandler --> Response
MiddleWareInterface --> Request
MiddleWareInterface --> Response
时序图
%%{
init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#ff8c1f',
'primaryTextColor': 'black',
'primaryBorderColor': '#7C0000',
'lineColor': '#38B239',
'secondaryColor': '#006100',
'tertiaryColor': '#fff'
}
}
}%%
sequenceDiagram
title: 中间件处理流程图(同过滤器)
autonumber
participant A as RequestMiddleWare
participant B as UserMiddleWare
participant C as DefaultMiddleWare
A->>B: Request
activate A
activate B
B->>C: Request
deactivate B
activate C
C-->>B: Response
deactivate C
activate B
B-->>A: Response
deactivate B
deactivate A
关键代码
php
class RequestHandler implements RequestHandlerInterface
{
/**
* @var array
*/
protected $middlewares = [];
/**
* @var string
*/
protected $defaultMiddleware = '';
/**
* Current offset
*
* @var int
*/
protected $offset = 0;
/**
* Initialize
*
* @param array $middlewares
* @param string $defaultMiddleware
*/
public function initialize(array $middlewares, string $defaultMiddleware): void
{
$this->offset = 0;
// init
$this->middlewares = $middlewares;
$this->defaultMiddleware = $defaultMiddleware;
}
/**
* Handler request by middleware
*
* @param ServerRequestInterface $request
*
* @return ResponseInterface
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
// Default middleware to handle request route
$middleware = $this->middlewares[$this->offset] ?? $this->defaultMiddleware;
/* @var MiddlewareInterface $bean */
$bean = Container::$instance->getSingleton($middleware);
// Next middleware
$this->offset++;
return $bean->process($request, $this);
}
/**
* Insert middleware at offset
*
* @param array $middlewares
* @param int|null $offset
*
* @throws HttpServerException
*/
public function insertMiddlewares(array $middlewares, int $offset = null): void
{
$offset = $offset ?? $this->offset;
if ($offset > $this->offset) {
throw new HttpServerException('Insert middleware offset must more than ' . $this->offset);
}
// Insert middlewares
array_splice($this->middlewares, $offset, 0, $middlewares);
}
}
php
class HttpDispatcher extends AbstractDispatcher
{
/**
* Default middleware to handler request
*
* @var string
*/
protected $defaultMiddleware = DefaultMiddleware::class;
/**
* Accept formatter
*
* @var AcceptResponseFormatter
* @Inject()
*/
protected $acceptFormatter;
/**
* @Inject("logger")
*
* @var Logger
*/
protected $logger;
/**
* Dispatch http request
*
* @param mixed ...$params
*/
public function dispatch(...$params): void
{
/**
* @var Request $request
* @var Response $response
*/
[$request, $response] = $params;
/* @var RequestHandler $requestHandler */
$requestHandler = Swoft::getBean(RequestHandler::class);
try {
$requestHandler->initialize($this->requestMiddlewares, $this->defaultMiddleware);
// Before request
$this->beforeRequest($request, $response);
// Trigger before handle event
Swoft::trigger(HttpServerEvent::BEFORE_REQUEST, null, $request, $response);
// Match router and handle
$request = $this->matchRouter($request);
// 此处 RequestHandler 中对 Request 处理后返回 Response.
$response = $requestHandler->handle($request);
} catch (Throwable $e) {
/** @var HttpErrorDispatcher $errDispatcher */
$errDispatcher = Swoft::getSingleton(HttpErrorDispatcher::class);
// Handle request error
$response = $errDispatcher->run($e, $response);
}
try {
// Format response content type
$response = $this->acceptFormatter->format($response);
// Trigger after request
Swoft::trigger(HttpServerEvent::AFTER_REQUEST, null, $response);
// After request
$this->afterRequest($response);
} catch (Throwable $e) {
Error::log('response error=%s(%d) at %s:%d', $e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine());
}
}
...
}
$response = $requestHandler->handle($request); 关键的处理语句,RequestHandler 对 Request 对象的处理,在内部最终演变为 MiddleWare 对 Request 对象的处理。并且 MiddleWare 对 Request 处理时,同时又引入了 RequestHandler 对象作为依赖,主要目的是,将 MiddleWare 的处理逻辑层层嵌套。例如:假设有两个中间件 M0, M1,优先用 M1 进行处理 Request 返回 Response,其处理最终依赖 M0 对 Request 处理。
php
Request req;
RequestHandler handler;
M1(req, handler) {
// do something for request.
// 此句实际等价于 res = M0(req);
Reponse res = handler->handle(request);
// do something for response.
return res;
}