Hyperf的中间件跟Java中的FilterChain类似,其作用是在调用controller之前对请求对象进行拦截,进行某些操作,再传递给下一个中间件或者直接返回输出响应。如Hyperf手册中所示,中间件是一个洋葱模型,其实现原理就是一个递归调用,代码思路如下:
<?php
interface MiddlewareInterface{
public function process(Response $response,RequestHandler $requestHandler);
}
class Middleware1 implements MiddlewareInterface{
public function process(Response $response,RequestHandler $requestHandler){
echo "Middleware1 before.<br/>";
$requestHandler->handle($response);
echo "Middleware1 after.<br/>";
return $response;
}
}
class Middleware2 implements MiddlewareInterface{
public function process(Response $response,RequestHandler $requestHandler){
echo "Middleware2 before.<br/>";
// 根据具体业务做一些校验
$valid = true;
if ($valid) {
$requestHandler->handle($response);
} else {
return $response->setResponse("stop at Middleware2");
}
echo "Middleware2 after.<br/>";
}
}
class Middleware3 implements MiddlewareInterface{
public function process(Response $response,RequestHandler $requestHandler){
echo "Middleware3 before.<br/>";
$requestHandler->handle($response);
echo "Middleware3 after.<br/>";
return $response;
}
}
class IndexController{
public function index(Response $response){
echo "controller.<br/>";
return $response->setResponse('this is index page');
}
}
class Response{
private $response;
public function getResponse(){
return $this->response;
}
public function setResponse($response){
$this->response = $response;
}
}
class RequestHandler{
private $controller;
private $action;
private $middlewareChain;
private $middlewareOffset = 0;
public function __construct($route)
{
$this->controller = new $route[0];
$this->action = $route[1];
$this->middlewareChain = $route[2];
}
public function handle($response){
if ($this->middlewareOffset == count($this->middlewareChain)){
return $this->controller($response);
} else {
$middleware = new $this->middlewareChain[$this->middlewareOffset++]();
return $middleware->process($response,$this);
}
}
public function controller($response){
return call_user_func([$this->controller,$this->action],$response);
}
}
// 匹配到的路由信息
$route = ['IndexController','index',[Middleware1::class,Middleware2::class,Middleware3::class]];
// 实例化,这里直接new,但在框架内所有对象的new操作都由容器进行管理注入
$requestHandler = new RequestHandler($route);
// 处理请求流程 & 响应
echo $requestHandler->handle(new Response())->getResponse();
根据请求匹配到具体路由信息,实例化一个Response对象传入RequestHandler的handle方法中,handle沿着中间件链进行递归调用,最终执行controller的方法返回Response对象,输出响应。上述示例响应如下:
可以在某个中间件截断请求处理流程,直接返回Response对象,例如将上述代码的Middleware2中的$valid改为false,响应如下:
中间件的应用场景有:
- 对请求头进行设置,如允许跨域
- 对公共的请求参数进行校验,如token校验、黑白名单校验
- 对请求对象进行预处理,如将JWT的payload解析获取用户id并存储在对象属性中,方便之后进行获取查询
来源:CSDN
作者:qq_41665505
链接:https://blog.csdn.net/qq_41665505/article/details/104610505