Server.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * This file is part of Hyperf.
  5. *
  6. * @link https://www.hyperf.io
  7. * @document https://hyperf.wiki
  8. * @contact group@hyperf.io
  9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
  10. */
  11. namespace Hyperf\HttpServer;
  12. use FastRoute\Dispatcher;
  13. use Hyperf\Context\RequestContext;
  14. use Hyperf\Context\ResponseContext;
  15. use Hyperf\Contract\ConfigInterface;
  16. use Hyperf\Contract\MiddlewareInitializerInterface;
  17. use Hyperf\Contract\OnRequestInterface;
  18. use Hyperf\Coordinator\Constants;
  19. use Hyperf\Coordinator\CoordinatorManager;
  20. use Hyperf\Dispatcher\HttpDispatcher;
  21. use Hyperf\Engine\Http\WritableConnection;
  22. use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher;
  23. use Hyperf\HttpMessage\Server\Request as Psr7Request;
  24. use Hyperf\HttpMessage\Server\Response as Psr7Response;
  25. use Hyperf\HttpServer\Contract\CoreMiddlewareInterface;
  26. use Hyperf\HttpServer\Event\RequestHandled;
  27. use Hyperf\HttpServer\Event\RequestReceived;
  28. use Hyperf\HttpServer\Event\RequestTerminated;
  29. use Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler;
  30. use Hyperf\HttpServer\Router\Dispatched;
  31. use Hyperf\HttpServer\Router\DispatcherFactory;
  32. use Hyperf\Server\Option;
  33. use Hyperf\Server\ServerFactory;
  34. use Hyperf\Support\SafeCaller;
  35. use Psr\Container\ContainerInterface;
  36. use Psr\EventDispatcher\EventDispatcherInterface;
  37. use Psr\Http\Message\ResponseInterface;
  38. use Psr\Http\Message\ServerRequestInterface;
  39. use Throwable;
  40. use function Hyperf\Coroutine\defer;
  41. use function Hyperf\Support\make;
  42. class Server implements OnRequestInterface, MiddlewareInitializerInterface
  43. {
  44. protected array $middlewares = [];
  45. protected ?CoreMiddlewareInterface $coreMiddleware = null;
  46. protected array $exceptionHandlers = [];
  47. protected ?string $serverName = null;
  48. protected ?EventDispatcherInterface $event = null;
  49. protected ?Option $option = null;
  50. public function __construct(
  51. protected ContainerInterface $container,
  52. protected HttpDispatcher $dispatcher,
  53. protected ExceptionHandlerDispatcher $exceptionHandlerDispatcher,
  54. protected ResponseEmitter $responseEmitter
  55. ) {
  56. if ($this->container->has(EventDispatcherInterface::class)) {
  57. $this->event = $this->container->get(EventDispatcherInterface::class);
  58. }
  59. }
  60. public function initCoreMiddleware(string $serverName): void
  61. {
  62. $this->serverName = $serverName;
  63. $this->coreMiddleware = $this->createCoreMiddleware();
  64. $config = $this->container->get(ConfigInterface::class);
  65. $this->middlewares = $config->get('middlewares.' . $serverName, []);
  66. $this->exceptionHandlers = $config->get('exceptions.handler.' . $serverName, $this->getDefaultExceptionHandler());
  67. $this->initOption();
  68. }
  69. public function onRequest($request, $response): void
  70. {
  71. try {
  72. CoordinatorManager::until(Constants::WORKER_START)->yield();
  73. [$psr7Request, $psr7Response] = $this->initRequestAndResponse($request, $response);
  74. $psr7Request = $this->coreMiddleware->dispatch($psr7Request);
  75. $this->option?->isEnableRequestLifecycle() && $this->event?->dispatch(new RequestReceived(
  76. request: $psr7Request,
  77. response: $psr7Response,
  78. server: $this->serverName
  79. ));
  80. /** @var Dispatched $dispatched */
  81. $dispatched = $psr7Request->getAttribute(Dispatched::class);
  82. $middlewares = $this->middlewares;
  83. $registeredMiddlewares = [];
  84. if ($dispatched->isFound()) {
  85. $registeredMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod());
  86. $middlewares = array_merge($middlewares, $registeredMiddlewares);
  87. }
  88. if ($this->option?->isMustSortMiddlewares() || $registeredMiddlewares) {
  89. $middlewares = MiddlewareManager::sortMiddlewares($middlewares);
  90. }
  91. $psr7Response = $this->dispatcher->dispatch($psr7Request, $middlewares, $this->coreMiddleware);
  92. } catch (Throwable $throwable) {
  93. // Delegate the exception to exception handler.
  94. $psr7Response = $this->container->get(SafeCaller::class)->call(function () use ($throwable) {
  95. return $this->exceptionHandlerDispatcher->dispatch($throwable, $this->exceptionHandlers);
  96. }, static function () {
  97. return (new Psr7Response())->withStatus(400);
  98. });
  99. } finally {
  100. if (isset($psr7Request) && $this->option?->isEnableRequestLifecycle()) {
  101. defer(fn () => $this->event?->dispatch(new RequestTerminated(
  102. request: $psr7Request,
  103. response: $psr7Response ?? null,
  104. exception: $throwable ?? null,
  105. server: $this->serverName
  106. )));
  107. $this->event?->dispatch(new RequestHandled(
  108. request: $psr7Request,
  109. response: $psr7Response ?? null,
  110. exception: $throwable ?? null,
  111. server: $this->serverName
  112. ));
  113. }
  114. // Send the Response to client.
  115. if (! isset($psr7Response) || ! $psr7Response instanceof ResponseInterface) {
  116. return;
  117. }
  118. if (isset($psr7Request) && $psr7Request->getMethod() === 'HEAD') {
  119. $this->responseEmitter->emit($psr7Response, $response, false);
  120. } else {
  121. $this->responseEmitter->emit($psr7Response, $response);
  122. }
  123. }
  124. }
  125. public function getServerName(): string
  126. {
  127. return $this->serverName;
  128. }
  129. /**
  130. * @return $this
  131. */
  132. public function setServerName(string $serverName)
  133. {
  134. $this->serverName = $serverName;
  135. return $this;
  136. }
  137. protected function initOption(): void
  138. {
  139. $ports = $this->container->get(ServerFactory::class)->getConfig()?->getServers();
  140. if (! $ports) {
  141. return;
  142. }
  143. foreach ($ports as $port) {
  144. if ($port->getName() === $this->serverName) {
  145. $this->option = $port->getOptions();
  146. }
  147. }
  148. $this->option ??= Option::make([]);
  149. $this->option->setMustSortMiddlewaresByMiddlewares($this->middlewares);
  150. }
  151. protected function createDispatcher(string $serverName): Dispatcher
  152. {
  153. $factory = $this->container->get(DispatcherFactory::class);
  154. return $factory->getDispatcher($serverName);
  155. }
  156. protected function getDefaultExceptionHandler(): array
  157. {
  158. return [
  159. HttpExceptionHandler::class,
  160. ];
  161. }
  162. protected function createCoreMiddleware(): CoreMiddlewareInterface
  163. {
  164. return make(CoreMiddleware::class, [$this->container, $this->serverName]);
  165. }
  166. /**
  167. * Initialize PSR-7 Request and Response objects.
  168. * @param mixed $request swoole request or psr server request
  169. * @param mixed $response swoole response or swow connection
  170. */
  171. protected function initRequestAndResponse($request, $response): array
  172. {
  173. ResponseContext::set($psr7Response = new Psr7Response());
  174. $psr7Response->setConnection(new WritableConnection($response));
  175. if ($request instanceof ServerRequestInterface) {
  176. $psr7Request = $request;
  177. } else {
  178. $psr7Request = Psr7Request::loadFromSwooleRequest($request);
  179. }
  180. RequestContext::set($psr7Request);
  181. return [$psr7Request, $psr7Response];
  182. }
  183. }