在 Hyperf 启动 中在注册服务事件(registerSwooleEvents)的时候会对回调方法和类进行实例化,然后指定回调方法 onRequest
,还有在对初始化回调的时候,对于 MiddlewareInitializerInterface
回调进行中间件初始化。所以在注册事件的时候就执行了 HttpServer 的两个方法
在构造方法中,定义了一个容器对象,两个分发起,还有一个返回发送器。
public function __construct(ContainerInterface $container, HttpDispatcher $dispatcher, ExceptionHandlerDispatcher $exceptionHandlerDispatcher, ResponseEmitter $responseEmitter)
{
$this->container = $container;
$this->dispatcher = $dispatcher;
$this->exceptionHandlerDispatcher = $exceptionHandlerDispatcher;
$this->responseEmitter = $responseEmitter;
}
在分发器处理方法中,接收的参数是 $request, $middlewares, $coreHandler ,并实例化 HttpRequestHandler 对象处理。也就是每次分发都是由一个新的Handle处理的。
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);
}
异常处理异常分发器,将异常 $throwable 分发到各个handler去。所以分发处理方法有两个参数
主要是处理业务中没有处理异常,根据匹配规则将异常交给指定的异常处理器。
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;
}
顾名思义,返回发送器就是将http请求的Response发送出去。主要原理就是将常规的Response构建成SwooleResponse进行发送。
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) {
}
}
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());
}
$this->middlewares = $config->get('middlewares.' . $serverName, []);
路由分发器由 hyperf/http-server/src/Router/DispatcherFactory.php
类进行处理,路由主要分两类,一类是配置路由,一类是注解路由。后续会专门针对Hyperf路由再写一章。
public function __construct()
{
$this->initAnnotationRoute(AnnotationCollector::list());
$this->initConfigRoute();
}
异常集合由默认的异常处理 HttpExceptionHandler 和配置文件 exceptions.php 中指定的为服务异常处理数组组成。简单点说,就是在 exceptions.php
文件配置HttpServer的多个异常处理。
回调接收到的参数的 Swoole\Http\Request
和 Swoole\Http\Response
这是 Swoole 中的请求和返回格式。initRequestAndResponse
方法就是将它们重构成 符合 psr7 标准的请求和返回。
这里还使用协程上下文Context还存储Request 和 Response,因为每个请求都是独立的,这样保证每个http请求拿到的Request和返回的Response都是独立的。
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];
}
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));
}
核心中间件的调度分两步,
Hyperf\HttpServer\Router\Handler
对象组成的数据,这里说明路由的回调处理发放,路由规则,还有中间件。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) {
}
}
if ($dispatched->isFound()) {
$registeredMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod());
$middlewares = array_merge($middlewares, $registeredMiddlewares);
}
所有中间件都有处理器,核心中间件处理器主要负责路由中callback(控制器业务)的执行。
处理之后会将Response的 Header Server 赋值 Hyperf。
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');
}
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;
}
onRequest最重要异步就是对http请求执行调度,其实就是控制中间件集合的调度。在前面步骤中已经获取所有中间件集合。$middlewares
[$request, $middlewares, $coreHandler] = $params;
$requestHandler = new HttpRequestHandler($middlewares, $coreHandler, $this->container);
return $requestHandler->handle($request);
整个调度器就是交由 HttpRequestHandler 对象进行控制。 handleRequest 方法就是控制各个中间件处理顺序,然后将处理后的Response 一个个中间件交下去。
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 处理。
catch (Throwable $throwable) {
// Delegate the exception to exception handler.
$psr7Response = $this->exceptionHandlerDispatcher->dispatch($throwable, $this->exceptionHandlers);
}
无论是处理完成的结果,还是异常结果,都会通过 responseEmitter将结果发送出去。
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 删除。