前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Hyperf 源码分析-HttpServer

Hyperf 源码分析-HttpServer

原创
作者头像
黄振炼
发布2023-11-03 09:31:35
3150
发布2023-11-03 09:31:35
举报
文章被收录于专栏:HcmsHcms

实例化

Hyperf 启动 中在注册服务事件(registerSwooleEvents)的时候会对回调方法和类进行实例化,然后指定回调方法 onRequest ,还有在对初始化回调的时候,对于 MiddlewareInitializerInterface 回调进行中间件初始化。所以在注册事件的时候就执行了 HttpServer 的两个方法

构建方法

在构造方法中,定义了一个容器对象,两个分发起,还有一个返回发送器。

  • HttpDispatcher
  • ExceptionHandlerDispatcher
  • ResponseEmitter
代码语言:php
复制
public function __construct(ContainerInterface $container, HttpDispatcher $dispatcher, ExceptionHandlerDispatcher $exceptionHandlerDispatcher, ResponseEmitter $responseEmitter)
  {
    $this->container = $container;
    $this->dispatcher = $dispatcher;
    $this->exceptionHandlerDispatcher = $exceptionHandlerDispatcher;
    
    $this->responseEmitter = $responseEmitter;
  }

Http分发器 HttpDispatcher

在分发器处理方法中,接收的参数是 $request, $middlewares, $coreHandler ,并实例化 HttpRequestHandler 对象处理。也就是每次分发都是由一个新的Handle处理的。

  • request 请求对象
  • middlewares 中间件
  • coreHandler 核心中间件
代码语言:php
复制
public function dispatch(...$params): ResponseInterface
{
  /**
  * @param RequestInterface $request
  * @param array $middlewares
  * @param MiddlewareInterface $coreHandler

  */
  [$request, $middlewares, $coreHandler] = $params;
  $requestHandler = new HttpRequestHandler($middlewares, $coreHandler, $this->container);
  return $requestHandler->handle($request);
}

异常处理分发器 exceptionHandlerDispatcher

异常处理异常分发器,将异常 $throwable 分发到各个handler去。所以分发处理方法有两个参数

  • throwable
  • handlers

主要是处理业务中没有处理异常,根据匹配规则将异常交给指定的异常处理器。

代码语言:php
复制
  public function dispatch(...$params)
    {
        /**
         * @param Throwable $throwable
         * @param string[] $handlers
         */
        [$throwable, $handlers] = $params;
        $response = Context::get(ResponseInterface::class);

        foreach ($handlers as $handler) {
            //找不到处理对象
            if (! $this->container->has($handler)) {
                throw new \InvalidArgumentException(sprintf('Invalid exception handler %s.', $handler));
            }
            //对象是否异常处理,还有是是否通过 isValid 校验,如果不通过,直接跳过处理下一个
            $handlerInstance = $this->container->get($handler);
            if (! $handlerInstance instanceof ExceptionHandler || ! $handlerInstance->isValid($throwable)) {
                continue;
            }
            $response = $handlerInstance->handle($throwable, $response);
            //是否继续往下处理
            if ($handlerInstance->isPropagationStopped()) {
                break;
            }
        }
        return $response;
    }

返回发送器 ResponseEmitter

顾名思义,返回发送器就是将http请求的Response发送出去。主要原理就是将常规的Response构建成SwooleResponse进行发送。

代码语言:php
复制
 public function emit(ResponseInterface $response, $swooleResponse, bool $withContent = true)
    {
        try {
            if (strtolower($swooleResponse->header['Upgrade'] ?? '') === 'websocket') {
                return;
            }
            $this->buildSwooleResponse($swooleResponse, $response);
            $content = $response->getBody();
            if ($content instanceof FileInterface) {
                $swooleResponse->sendfile($content->getFilename());
                return;
            }

            if ($withContent) {
                $swooleResponse->end((string) $content);
            } else {
                $swooleResponse->end();
            }
        } catch (\Throwable $exception) {
        }
    }

初始化中间件 initCoreMiddleware

代码语言:php
复制
public function initCoreMiddleware(string $serverName): void
  {
    $this->serverName = $serverName;
    $this->coreMiddleware = $this->createCoreMiddleware();
    $this->routerDispatcher = $this->createDispatcher($serverName);

    $config = $this->container->get(ConfigInterface::class);
    $this->middlewares = $config->get('middlewares.' . $serverName, []);
    $this->exceptionHandlers = $config->get('exceptions.handler.' . $serverName, $this->getDefaultExceptionHandler());
  }

构建中间件

  1. createCoreMiddleware 创建实例化核心中间件,然后由 HttpDispatcher 分发。
  2. 获取配置文件中的全局中间件。

$this->middlewares = $config->get('middlewares.' . $serverName, []);

创建路由分发器

路由分发器由 hyperf/http-server/src/Router/DispatcherFactory.php 类进行处理,路由主要分两类,一类是配置路由,一类是注解路由。后续会专门针对Hyperf路由再写一章。

代码语言:php
复制
public function __construct()
  {
    $this->initAnnotationRoute(AnnotationCollector::list());
    $this->initConfigRoute();
  }

异常处理集合

异常集合由默认的异常处理 HttpExceptionHandler 和配置文件 exceptions.php 中指定的为服务异常处理数组组成。简单点说,就是在 exceptions.php 文件配置HttpServer的多个异常处理。

请求回调方法 onRequest

初始化请求和返回 initRequestAndResponse

回调接收到的参数的 Swoole\Http\RequestSwoole\Http\Response 这是 Swoole 中的请求和返回格式。initRequestAndResponse方法就是将它们重构成 符合 psr7 标准的请求和返回。

这里还使用协程上下文Context还存储Request 和 Response,因为每个请求都是独立的,这样保证每个http请求拿到的Request和返回的Response都是独立的。

代码语言:php
复制
protected function initRequestAndResponse($request, $response): array
  {
    Context::set(ResponseInterface::class, $psr7Response = new Psr7Response());

    if ($request instanceof ServerRequestInterface) {
      $psr7Request = $request;
    } else {
      $psr7Request = Psr7Request::loadFromSwooleRequest($request);
      $psr7Response->setConnection(new SwooleConnection($response));
    }

    Context::set(ServerRequestInterface::class, $psr7Request);
    return [$psr7Request, $psr7Response];
  }

Hyperf\HttpMessage\Server\Request

Hyperf\HttpMessage\Server\Response

核心中间件 CoreMiddleware

调度 dispatch

代码语言:php
复制
public function dispatch(ServerRequestInterface $request): ServerRequestInterface
  {
    $routes = $this->dispatcher->dispatch($request->getMethod(), $request->getUri()->getPath());

    $dispatched = new Dispatched($routes);

    return Context::set(ServerRequestInterface::class, $request->withAttribute(Dispatched::class, $dispatched));
  }

核心中间件的调度分两步,

  • 通过自身的分发器价获取路由数组 $routes,打印 $routes 信息发现,里面有一个 Hyperf\HttpServer\Router\Handler 对象组成的数据,这里说明路由的回调处理发放,路由规则,还有中间件。
代码语言:php
复制
array(3) {
  [0]=>
  int(1)
  [1]=>
  object(Hyperf\HttpServer\Router\Handler)#1298 (3) {
    ["callback"]=>
    array(2) {
      [0]=>
      string(49) "App\Application\Admin\Controller\AccessController"
      [1]=>
      string(5) "lists"
    }
    ["route"]=>
    string(25) "/admin/access/index/lists"
    ["options"]=>
    array(1) {
      ["middleware"]=>
      array(1) {
        [0]=>
        string(48) "App\Application\Admin\Middleware\AdminMiddleware"
      }
    }
  }
  [2]=>
  array(0) {
  }
}
  • New 一个新的路由分发器,将获得的 $routes 作为路由分发的构造参数。然后将路由分发器 $dispatched 加入到请求对象 $request中,再与配置中间件合并成为最后的中间件集合。
代码语言:php
复制
if ($dispatched->isFound()) {
  $registeredMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod());
  $middlewares = array_merge($middlewares, $registeredMiddlewares);
}

处理器 process

所有中间件都有处理器,核心中间件处理器主要负责路由中callback(控制器业务)的执行。

处理之后会将Response的 Header Server 赋值 Hyperf。

代码语言:javascript
复制
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
  {
    $request = Context::set(ServerRequestInterface::class, $request);

    /** @var Dispatched $dispatched */
    $dispatched = $request->getAttribute(Dispatched::class);

    if (! $dispatched instanceof Dispatched) {
      throw new ServerException(sprintf('The dispatched object is not a %s object.', Dispatched::class));
    }

    $response = null;
    switch ($dispatched->status) {
      case Dispatcher::NOT_FOUND:
      $response = $this->handleNotFound($request);
      break;
      case Dispatcher::METHOD_NOT_ALLOWED:
      $response = $this->handleMethodNotAllowed($dispatched->params, $request);
      break;
      case Dispatcher::FOUND:
      $response = $this->handleFound($dispatched, $request);
      break;
    }
    if (! $response instanceof ResponseInterface) {
      $response = $this->transferToResponse($response, $request);
    }
    return $response->withAddedHeader('Server', 'Hyperf');
  }
  • 通过Request 获取路由分发器 $dispatched
  • 查看路由状态,调用路由中在callback方法(也就是具体的业务实现控制器),具体看
代码语言:javascript
复制
protected function handleFound(Dispatched $dispatched, ServerRequestInterface $request)
  {
    if ($dispatched->handler->callback instanceof Closure) {
      $parameters = $this->parseClosureParameters($dispatched->handler->callback, $dispatched->params);
      $response = call($dispatched->handler->callback, $parameters);
    } else {
      [$controller, $action] = $this->prepareHandler($dispatched->handler->callback);
      $controllerInstance = $this->container->get($controller);
      if (! method_exists($controllerInstance, $action)) {
        // Route found, but the handler does not exist.
        throw new ServerErrorHttpException('Method of class does not exist.');
      }
      $parameters = $this->parseMethodParameters($controller, $action, $dispatched->params);
      $response = $controllerInstance->{$action}(...$parameters);
    }
    return $response;
  }
  • 返回 $response

请求调度器 dispatcher

onRequest最重要异步就是对http请求执行调度,其实就是控制中间件集合的调度。在前面步骤中已经获取所有中间件集合。$middlewares

代码语言:javascript
复制
[$request, $middlewares, $coreHandler] = $params;
$requestHandler = new HttpRequestHandler($middlewares, $coreHandler, $this->container);
return $requestHandler->handle($request);

HttpRequestHandler

整个调度器就是交由 HttpRequestHandler 对象进行控制。 handleRequest 方法就是控制各个中间件处理顺序,然后将处理后的Response 一个个中间件交下去。

代码语言:javascript
复制
protected function handleRequest($request)
  {
    if (! isset($this->middlewares[$this->offset]) && ! empty($this->coreHandler)) {
      $handler = $this->coreHandler;
    } else {
      $handler = $this->middlewares[$this->offset];
      is_string($handler) && $handler = $this->container->get($handler);
    }
    if (! method_exists($handler, 'process')) {
      throw new InvalidArgumentException(sprintf('Invalid middleware, it has to provide a process() method.'));
    }
    return $handler->process($request, $this->next());
  }

protected function next(): self
  {
    ++$this->offset;
    return $this;
  }

异常处理

整个onRequest 回调方法处理抛出的异常$throwable 都会交由 exceptionHandlerDispatcher调度。就是将异常交给一个个 exceptionHandler 处理。

代码语言:javascript
复制
catch (Throwable $throwable) {
  // Delegate the exception to exception handler.
  $psr7Response = $this->exceptionHandlerDispatcher->dispatch($throwable, $this->exceptionHandlers);
}

返回结果发送

无论是处理完成的结果,还是异常结果,都会通过 responseEmitter将结果发送出去。

代码语言:javascript
复制
finally {
  // Send the Response to client.
  if (! isset($psr7Response)) {
    return;
  }
  if (isset($psr7Request) && $psr7Request->getMethod() === 'HEAD') {
    $this->responseEmitter->emit($psr7Response, $response, false);
  } else {
    $this->responseEmitter->emit($psr7Response, $response, true);
  }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实例化
    • 构建方法
      • Http分发器 HttpDispatcher
      • 异常处理分发器 exceptionHandlerDispatcher
      • 返回发送器 ResponseEmitter
    • 初始化中间件 initCoreMiddleware
      • 构建中间件
      • 创建路由分发器
      • 异常处理集合
  • 请求回调方法 onRequest
    • 初始化请求和返回 initRequestAndResponse
      • Hyperf\HttpMessage\Server\Request
      • Hyperf\HttpMessage\Server\Response
    • 核心中间件 CoreMiddleware
      • 调度 dispatch
      • 处理器 process
    • 请求调度器 dispatcher
      • HttpRequestHandler
    • 异常处理
      • 返回结果发送
      相关产品与服务
      消息队列 TDMQ
      消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
      http://www.vxiaotou.com