声明一个中间件

中间件是用于控制 请求到达 和 响应请求 的整个流程的,通常用于对请求进行过滤验证处理,当你需要对请求或响应作出对应的修改或处理,或想调整请求处理的流程时均可以使用中间件来实现。

定义中间件

只需要实现了 Swoft\Http\Server\Contract\MiddlewareInterface 接口均为一个合法的中间件,其中 process() 方法为该中间件逻辑处理方法。

  1. namespace App\Http\Middleware;
  2. use Psr\Http\Message\ResponseInterface;
  3. use Psr\Http\Message\ServerRequestInterface;
  4. use Psr\Http\Server\RequestHandlerInterface;
  5. use Swoft\Bean\Annotation\Mapping\Bean;
  6. use Swoft\Http\Server\Contract\MiddlewareInterface;
  7. /**
  8. * @Bean()
  9. */
  10. class ControllerMiddleware implements MiddlewareInterface
  11. {
  12. /**
  13. * Process an incoming server request.
  14. *
  15. * @param ServerRequestInterface $request
  16. * @param RequestHandlerInterface $handler
  17. *
  18. * @return ResponseInterface
  19. * @inheritdoc
  20. */
  21. public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
  22. {
  23. $response = $handler->handle($request);
  24. return $response;
  25. }
  26. }

使用

配置全局中间件

当你的自定义中间件需要全局请求应用,则可以考虑将此中间件作为全局中间件去使用,只需在 Bean 配置文件内配置 httpDispatcher 的 middlewares 属性,在数组中加入你的自定义中间件的命名空间地址,相关配置通常在 app/bean.php 内

  1. return [
  2. ...
  3. 'httpDispatcher'=>[
  4. 'middlewares'=>[
  5. AuthMiddleware::class,
  6. ApiMiddleware::class
  7. ]
  8. ]
  9. ...
  10. ]

通过注解使用

通过 @Middleware@Middlewares, 可以很方便的配置中间件到当前的 Controller 和 Action 内

当将此注解应用于 Controller 上,则作用域为整个 Controller
将此注解应用于 Action 上,则作用域仅为当前的 Action
@Middleware 用于配置单个中间件
@Middlewares 显而易见的是用于配置一组 @Middleware,按照定义顺序依次执行

  1. namespace App\Http\Controller;
  2. use App\Http\Middleware\ApiMiddleware;
  3. use App\Http\Middleware\IndexMiddleware;
  4. use App\Http\Middleware\ControllerMiddleware;
  5. use Swoft\Http\Server\Annotation\Mapping\Controller;
  6. use Swoft\Http\Server\Annotation\Mapping\Middleware;
  7. use Swoft\Http\Server\Annotation\Mapping\Middlewares;
  8. use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
  9. /**
  10. * @Controller()
  11. * @Middlewares({
  12. * @Middleware(ApiMiddleware::class),
  13. * @Middleware(ControllerMiddleware::class)
  14. * })
  15. */
  16. class MiddlewareController
  17. {
  18. /**
  19. * @RequestMapping()
  20. * @Middleware(IndexMiddleware::class)
  21. */
  22. public function index(){
  23. return "MiddlewareController";
  24. }
  25. }

应用

提前拦截请求

注意: 拦截要在 $handler->handle($request) 之前

  1. namespace App\Http\Middleware;
  2. use Psr\Http\Message\ResponseInterface;
  3. use Psr\Http\Message\ServerRequestInterface;
  4. use Psr\Http\Server\RequestHandlerInterface;
  5. use Swoft\Bean\Annotation\Mapping\Bean;
  6. use Swoft\Context\Context;
  7. use Swoft\Http\Server\Contract\MiddlewareInterface;
  8. /**
  9. * @Bean()
  10. */
  11. class SomeMiddleware implements MiddlewareInterface
  12. {
  13. /**
  14. * Process an incoming server request.
  15. * @param ServerRequestInterface $request
  16. * @param RequestHandlerInterface $handler
  17. * @return ResponseInterface
  18. * @inheritdoc
  19. */
  20. public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
  21. {
  22. $path = $request->getUri()->getPath();
  23. if ($path === '/favicon.ico') {
  24. $response = Context::mustGet()->getResponse();
  25. return $response->withStatus(404);
  26. }
  27. return $handler->handle($request);
  28. }
  29. }

跨域设置

  1. namespace App\Http\Middleware;
  2. use Psr\Http\Message\ResponseInterface;
  3. use Psr\Http\Message\ServerRequestInterface;
  4. use Psr\Http\Server\RequestHandlerInterface;
  5. use Swoft\Bean\Annotation\Mapping\Bean;
  6. use Swoft\Http\Server\Contract\MiddlewareInterface;
  7. /**
  8. * @Bean()
  9. */
  10. class CorsMiddleware implements MiddlewareInterface
  11. {
  12. /**
  13. * Process an incoming server request.
  14. * @param ServerRequestInterface $request
  15. * @param RequestHandlerInterface $handler
  16. * @return ResponseInterface
  17. * @inheritdoc
  18. */
  19. public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
  20. {
  21. if ('OPTIONS' === $request->getMethod()) {
  22. $response = Context::mustGet()->getResponse();
  23. return $this->configResponse($response);
  24. }
  25. $response = $handler->handle($request);
  26. return $this->configResponse($response);
  27. }
  28. private function configResponse(ResponseInterface $response)
  29. {
  30. return $response
  31. ->withHeader('Access-Control-Allow-Origin', 'http://mysite')
  32. ->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
  33. ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
  34. }
  35. }

用户JWT登陆验证

  1. namespace App\Http\Middleware;
  2. use Psr\Http\Message\ResponseInterface;
  3. use Psr\Http\Message\ServerRequestInterface;
  4. use Psr\Http\Server\RequestHandlerInterface;
  5. use Swoft\Bean\Annotation\Mapping\Bean;
  6. use Swoft\Context\Context;
  7. use Swoft\Http\Server\Contract\MiddlewareInterface;
  8. /**
  9. * @Bean()
  10. */
  11. class AuthMiddleware implements MiddlewareInterface
  12. {
  13. /**
  14. * Process an incoming server request.
  15. * @param ServerRequestInterface $request
  16. * @param RequestHandlerInterface $handler
  17. * @return ResponseInterface
  18. * @inheritdoc
  19. */
  20. public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
  21. {
  22. // before request handle
  23. // 判断token
  24. $token = $request->getHeaderLine("token");
  25. $type = \config('jwt.type');
  26. $public = \config('jwt.publicKey');
  27. try {
  28. $auth = JWT::decode($token, $public, ['type' => $type]);
  29. $request->user = $auth->user;
  30. } catch (\Exception $e) {
  31. $json = ['code'=>0,'msg'=>'授权失败']
  32. $response = Context::mustGet()->getResponse();
  33. return $response->withData($json);
  34. }
  35. $response = $handler->handle($request);
  36. return $response;
  37. // after request handle
  38. }
  39. }