Swoft2 开源框架中的过滤器实现

概述

针对请求响应式(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;
}