diff --git a/HttpServer/Events/OnRequest.php b/HttpServer/Events/OnRequest.php index 4917f8dd..58fb3d52 100644 --- a/HttpServer/Events/OnRequest.php +++ b/HttpServer/Events/OnRequest.php @@ -9,6 +9,7 @@ use HttpServer\Abstracts\Callback; use HttpServer\Exception\ExitException; use HttpServer\Http\Request as HRequest; use HttpServer\Http\Response as HResponse; +use HttpServer\Route\Router; use Snowflake\Error\Logger; use Snowflake\Event; use Snowflake\Snowflake; @@ -24,87 +25,88 @@ class OnRequest extends Callback { - public Event $event; - public Logger $logger; + public Event $event; + public Logger $logger; - /** - * @throws Exception - */ - public function init() - { - $this->event = Snowflake::app()->getEvent(); - } + public Router $router; - /** - * @param Request $request - * @param Response $response - * @return void - * @throws Exception - */ - public function onHandler(Request $request, Response $response): mixed - { - try { - defer(function () { - fire(Event::SYSTEM_RESOURCE_RELEASES); - }); - /** @var HRequest $request */ - [$request, $response] = OnRequest::createContext($request, $response); - - $this->event->dispatch(Event::EVENT_BEFORE_REQUEST, [$request]); - - $result = $request->dispatch(); - - $this->event->dispatch(Event::EVENT_AFTER_REQUEST, [$request, $result]); - - return $result; - } catch (ExitException | Error | \Throwable $exception) { - $this->addError($exception, 'throwable'); - return $this->sendErrorMessage($request, $response, $exception); - } - } + /** + * @throws Exception + */ + public function init() + { + $this->event = Snowflake::app()->getEvent(); + $this->router = Snowflake::app()->getRouter(); + } - /** - * @param $request - * @param $response - * @return array - */ - public static function createContext($request, $response): array - { - return [HRequest::create($request), HResponse::create($response)]; - } + /** + * @param Request $request + * @param Response $response + * @return void + * @throws Exception + */ + public function onHandler(Request $request, Response $response): mixed + { + try { + defer(function () { + fire(Event::SYSTEM_RESOURCE_RELEASES); + }); + /** @var HRequest $request */ + /** @var HResponse $response */ + [$request, $response] = OnRequest::createContext($request, $response); + if ($request->is('favicon.ico')) { + return $response->send('', 404); + } + return $this->router->dispatch(); + } catch (ExitException | Error | \Throwable $exception) { + $this->addError($exception, 'throwable'); + return $this->sendErrorMessage($request, $response, $exception); + } + } - /** - * @param $sRequest - * @param $sResponse - * @param $exception - * @return bool|string - * @throws Exception - */ - protected function sendErrorMessage($sRequest, $sResponse, $exception): bool|string - { - $this->addError($exception, 'throwable'); - if ($sResponse instanceof Response) { - [$sRequest, $sResponse] = [HRequest::create($sRequest), HResponse::create($sResponse)]; - } + /** + * @param $request + * @param $response + * @return array + */ + public static function createContext($request, $response): array + { + return [HRequest::create($request), HResponse::create($response)]; + } - $this->event->dispatch(Event::EVENT_AFTER_REQUEST, [$sRequest, $exception]); - $headers = $sRequest->headers->get('access-control-request-headers'); - $methods = $sRequest->headers->get('access-control-request-method'); + /** + * @param $sRequest + * @param $sResponse + * @param $exception + * @return bool|string + * @throws Exception + */ + protected function sendErrorMessage($sRequest, $sResponse, $exception): bool|string + { + $this->addError($exception, 'throwable'); + if ($sResponse instanceof Response) { + [$sRequest, $sResponse] = [HRequest::create($sRequest), HResponse::create($sResponse)]; + } - $sResponse->addHeader('Access-Control-Allow-Origin', '*'); - $sResponse->addHeader('Access-Control-Allow-Headers', $headers); - $sResponse->addHeader('Access-Control-Request-Method', $methods); + $this->event->dispatch(Event::EVENT_AFTER_REQUEST, [$sRequest, $exception]); - if (!($exception instanceof ExitException)) { - return $sResponse->send(\logger()->exception($exception), 200); - } else { - return $sResponse->send($exception->getMessage(), 200); - } - } + $headers = $sRequest->headers->get('access-control-request-headers'); + $methods = $sRequest->headers->get('access-control-request-method'); + + $sResponse->addHeader('Access-Control-Allow-Origin', '*'); + $sResponse->addHeader('Access-Control-Allow-Headers', $headers); + $sResponse->addHeader('Access-Control-Request-Method', $methods); + + if (!($exception instanceof ExitException)) { + return $sResponse->send(\logger()->exception($exception), 200); + } else { + return $sResponse->send($exception->getMessage(), 200); + } + } } diff --git a/HttpServer/Route/Node.php b/HttpServer/Route/Node.php index 7445776e..2ca915c2 100644 --- a/HttpServer/Route/Node.php +++ b/HttpServer/Route/Node.php @@ -31,539 +31,540 @@ use function Input; class Node extends HttpService { - public string $path = ''; - public int $index = 0; - public string $method = ''; + public string $path = ''; + public int $index = 0; + public string $method = ''; - /** @var Node[] $childes */ - public array $childes = []; + /** @var Node[] $childes */ + public array $childes = []; - public array $group = []; + public array $group = []; - private string $_error = ''; + private string $_error = ''; - private array $rules = []; + private array $rules = []; - private string $_dataType = ''; + private string $_dataType = ''; - /** @var ?Closure|?array */ - public Closure|array|null $handler; - public string $htmlSuffix = '.html'; - public bool $enableHtmlSuffix = false; - public array $namespace = []; - public array $middleware = []; + /** @var ?Closure|?array */ + public Closure|array|null $handler; + public string $htmlSuffix = '.html'; + public bool $enableHtmlSuffix = false; + public array $namespace = []; + public array $middleware = []; - /** @var array|Closure */ - public Closure|array $callback = []; + /** @var array|Closure */ + public Closure|array $callback = []; - private string $_alias = ''; + private string $_alias = ''; - private array $_interceptors = []; - private array $_after = []; - private array $_limits = []; + private array $_interceptors = []; + private array $_after = []; + private array $_limits = []; - /** - * @param string $dataType - */ - public function setDataType(string $dataType) - { - $this->_dataType = $dataType; - } + /** + * @param string $dataType + */ + public function setDataType(string $dataType) + { + $this->_dataType = $dataType; + } - /** - * @param string $data - * @return mixed - */ - public function unpack(string $data): mixed - { - if ($this->_dataType == RpcProducer::PROTOCOL_JSON) { - return json_decode($data, true); - } - if ($this->_dataType == RpcProducer::PROTOCOL_SERIALIZE) { - return unserialize($data); - } - return $data; - } + /** + * @param string $data + * @return mixed + */ + public function unpack(string $data): mixed + { + if ($this->_dataType == RpcProducer::PROTOCOL_JSON) { + return json_decode($data, true); + } + if ($this->_dataType == RpcProducer::PROTOCOL_SERIALIZE) { + return unserialize($data); + } + return $data; + } - /** - * @param $handler - * @return Node - * @throws - */ - public function bindHandler($handler): static - { - if (is_string($handler) && str_contains($handler, '@')) { - list($controller, $action) = explode('@', $handler); - if (!empty($this->namespace)) { - $controller = implode('\\', $this->namespace) . '\\' . $controller; - } - $this->handler = $this->getReflect($controller, $action); - } else if ($handler != null && !is_callable($handler, true)) { - $this->_error = 'Controller is con\'t exec.'; - } else if ($handler instanceof Closure) { - $this->handler = $handler; - } else { - [$controller, $action] = $this->handler = $handler; - if (!($controller instanceof Controller)) { - return $this; - } - $this->annotationInject($controller::class, $action); - } - if (!empty($this->handler)) { - $this->callback = Reduce::reduce($this->createDispatch(), $this->annotation()); - } - return $this; - } + /** + * @param $handler + * @return Node + * @throws + */ + public function bindHandler($handler): static + { + if (is_string($handler) && str_contains($handler, '@')) { + list($controller, $action) = explode('@', $handler); + if (!empty($this->namespace)) { + $controller = implode('\\', $this->namespace) . '\\' . $controller; + } + $this->handler = $this->getReflect($controller, $action); + } else if ($handler != null && !is_callable($handler, true)) { + $this->_error = 'Controller is con\'t exec.'; + } else if ($handler instanceof Closure) { + $this->handler = $handler; + } else { + [$controller, $action] = $this->handler = $handler; + if (!($controller instanceof Controller)) { + return $this; + } + $this->annotationInject($controller::class, $action); + } + if (!empty($this->handler)) { + $this->callback = Reduce::reduce($this->createDispatch(), $this->annotation()); + } + return $this; + } - /** - * @return Closure - */ - public function createDispatch(): Closure - { - return function () { - $dispatchParam = Context::getContext('dispatch-param'); - if (empty($dispatchParam)) { - $dispatchParam = [\request()]; - } + /** + * @return Closure + */ + public function createDispatch(): Closure + { + return function () { + $dispatchParam = Context::getContext('dispatch-param'); + if (empty($dispatchParam)) { + $dispatchParam = [\request()]; + } // return call_user_func($this->handler, ...$dispatchParam); - return \aop($this->handler, $dispatchParam); - }; - } + return \aop($this->handler, $dispatchParam); + }; + } - /** - * @return array - */ - protected function annotation(): array - { - $middleWares = $this->getMiddleWares(); - $middleWares = $this->annotation_limit($this, $middleWares); - $middleWares = $this->annotation_interceptor($this, $middleWares); - return $middleWares; - } + /** + * @return array + */ + protected function annotation(): array + { + $middleWares = $this->getMiddleWares(); + $middleWares = $this->annotation_limit($this, $middleWares); + $middleWares = $this->annotation_interceptor($this, $middleWares); + return $middleWares; + } - /** - * @param Node $node - * @param $middleWares - * @return array - */ - protected function annotation_interceptor(Node $node, $middleWares = []): array - { - if (!$node->hasInterceptor()) { - return $middleWares; - } - foreach ($node->getInterceptor() as $item) { - $middleWares[] = $item; - } - return $middleWares; - } + /** + * @param Node $node + * @param $middleWares + * @return array + */ + protected function annotation_interceptor(Node $node, $middleWares = []): array + { + if (!$node->hasInterceptor()) { + return $middleWares; + } + foreach ($node->getInterceptor() as $item) { + $middleWares[] = $item; + } + return $middleWares; + } - /** - * @param Node $node - * @param $middleWares - * @return array - */ - protected function annotation_limit(Node $node, $middleWares = []): array - { - if (!$node->hasLimits()) { - return $middleWares; - } - foreach ($node->getLimits() as $item) { - $middleWares[] = $item; - } - return $middleWares; - } + /** + * @param Node $node + * @param $middleWares + * @return array + */ + protected function annotation_limit(Node $node, $middleWares = []): array + { + if (!$node->hasLimits()) { + return $middleWares; + } + foreach ($node->getLimits() as $item) { + $middleWares[] = $item; + } + return $middleWares; + } - /** - * @return bool - */ - #[Pure] public function hasInterceptor(): bool - { - return count($this->_interceptors) > 0; - } + /** + * @return bool + */ + #[Pure] public function hasInterceptor(): bool + { + return count($this->_interceptors) > 0; + } - /** - * @return bool - */ - #[Pure] public function hasLimits(): bool - { - return count($this->_limits) > 0; - } + /** + * @return bool + */ + #[Pure] public function hasLimits(): bool + { + return count($this->_limits) > 0; + } - /** - * @param null $response - * @return mixed - * @throws Exception - */ - public function afterDispatch($response = null): mixed - { - if (is_object($this->_after[0])) { - return call_user_func($this->_after, \request(), $response); - } - foreach ($this->_after as $value) { - call_user_func($value, \request(), $response); - } - return $this->_after; - } + /** + * @param null $response + * @return mixed + * @throws Exception + */ + public function afterDispatch($response = null): mixed + { + if (is_object($this->_after[0])) { + return call_user_func($this->_after, \request(), $response); + } + foreach ($this->_after as $value) { + call_user_func($value, \request(), $response); + } + return $this->_after; + } - /** - * @return array - */ - public function getInterceptor(): array - { - return $this->_interceptors; - } + /** + * @return array + */ + public function getInterceptor(): array + { + return $this->_interceptors; + } - /** - * @return array - */ - public function getAfters(): array - { - return $this->_after; - } + /** + * @return array + */ + public function getAfters(): array + { + return $this->_after; + } - /** - * @return bool - */ - #[Pure] public function hasAfter(): bool - { - return count($this->_after) > 0; - } + /** + * @return bool + */ + #[Pure] public function hasAfter(): bool + { + return count($this->_after) > 0; + } - /** - * @return array - */ - public function getLimits(): array - { - return $this->_limits; - } + /** + * @return array + */ + public function getLimits(): array + { + return $this->_limits; + } - /** - * @param $request - * @return bool - */ - public function methodAllow(Request $request): bool - { - if ($this->method == $request->getMethod()) { - return true; - } - return $this->method == 'any'; - } + /** + * @param $request + * @return bool + */ + public function methodAllow(Request $request): bool + { + if ($this->method == $request->getMethod()) { + return true; + } + return $this->method == 'any'; + } - /** - * @return bool - * @throws Exception - */ - public function checkSuffix(): bool - { - if ($this->enableHtmlSuffix) { - $url = request()->getUri(); - $nowLength = strlen($this->htmlSuffix); - if (strpos($url, $this->htmlSuffix) !== strlen($url) - $nowLength) { - return false; - } - } - return true; - } + /** + * @return bool + * @throws Exception + */ + public function checkSuffix(): bool + { + if ($this->enableHtmlSuffix) { + $url = request()->getUri(); + $nowLength = strlen($this->htmlSuffix); + if (strpos($url, $this->htmlSuffix) !== strlen($url) - $nowLength) { + return false; + } + } + return true; + } - /** - * @param string $controller - * @param string $action - * @return null|array - * @throws Exception - */ - private function getReflect(string $controller, string $action): ?array - { - try { - $reflect = Snowflake::getDi()->getReflect($controller); - if (empty($reflect)) { - throw new Exception($controller . ' Class is con\'t Instantiable.'); - } - if (!empty($action) && !$reflect->hasMethod($action)) { - throw new Exception('method ' . $action . ' not exists at ' . $controller . '.'); - } + /** + * @param string $controller + * @param string $action + * @return null|array + * @throws Exception + */ + private function getReflect(string $controller, string $action): ?array + { + try { + $reflect = Snowflake::getDi()->getReflect($controller); + if (empty($reflect)) { + throw new Exception($controller . ' Class is con\'t Instantiable.'); + } + if (!empty($action) && !$reflect->hasMethod($action)) { + throw new Exception('method ' . $action . ' not exists at ' . $controller . '.'); + } - $this->annotationInject($reflect->getName(), $action); + $this->annotationInject($reflect->getName(), $action); - return [$reflect->newInstance(), $action]; - } catch (Throwable $exception) { - $this->_error = $exception->getMessage(); - $this->addError($exception, 'router'); - return null; - } - } + return [$reflect->newInstance(), $action]; + } catch (Throwable $exception) { + $this->_error = $exception->getMessage(); + $this->addError($exception, 'router'); + return null; + } + } - /** - * @param Closure|array|string $handler - * @throws Exception - */ - public function addInterceptor(Closure|string|array $handler) - { - if (!is_array($handler) || is_object($handler[0])) { - $handler = [$handler]; - } - foreach ($handler as $closure) { - if (in_array($closure, $this->_interceptors)) { - continue; - } - $this->_interceptors[] = $closure; - } - } + /** + * @param Closure|array|string $handler + * @throws Exception + */ + public function addInterceptor(Closure|string|array $handler) + { + if (!is_array($handler) || is_object($handler[0])) { + $handler = [$handler]; + } + foreach ($handler as $closure) { + if (in_array($closure, $this->_interceptors)) { + continue; + } + $this->_interceptors[] = $closure; + } + } - /** - * @param string $className - * @param string $action - * @return Node - * @throws Exception - */ - public function annotationInject(string $className, string $action): Node - { - $annotation = annotation()->getMethods($className, $action); - if (empty($annotation)) { - return $this->injectRules($className, $action); - } - foreach ($annotation as $attribute) { - if ($attribute instanceof Interceptor) { - $this->addInterceptor($attribute->interceptor); - } - if ($attribute instanceof After) { - $this->addAfter($attribute->after); - } - if ($attribute instanceof Middleware) { - $this->addMiddleware($attribute->middleware); - } - if ($attribute instanceof Limits) { - $this->addLimits($attribute->limits); - } - } - return $this->injectRules($className, $action); - } + /** + * @param string $className + * @param string $action + * @return Node + * @throws Exception + */ + public function annotationInject(string $className, string $action): Node + { + $annotation = annotation()->getMethods($className, $action); + if (empty($annotation)) { + return $this->injectRules($className, $action); + } + foreach ($annotation as $attribute) { + if ($attribute instanceof Interceptor) { + $this->addInterceptor($attribute->interceptor); + } + if ($attribute instanceof After) { + $this->addAfter($attribute->after); + } + if ($attribute instanceof Middleware) { + $this->addMiddleware($attribute->middleware); + } + if ($attribute instanceof Limits) { + $this->addLimits($attribute->limits); + } + } + return $this->injectRules($className, $action); + } - /** - * @param string $controller - * @param string $action - * @return $this - * @throws \Exception - */ - private function injectRules(string $controller, string $action): static - { - /** @var HttpFilter $filter */ - $filter = Snowflake::app()->get('filter'); - $this->rules = $filter->getRules($controller, $action); + /** + * @param string $controller + * @param string $action + * @return $this + * @throws \Exception + */ + private function injectRules(string $controller, string $action): static + { + /** @var HttpFilter $filter */ + $filter = Snowflake::app()->get('filter'); + $this->rules = $filter->getRules($controller, $action); - return $this; - } + return $this; + } - /** - * @param Closure|array|string $handler - * @throws Exception - */ - public function addAfter(Closure|string|array $handler) - { - if (!is_array($handler) || is_object($handler[0])) { - $handler = [$handler]; - } - foreach ($handler as $closure) { - if (in_array($closure, $this->_after)) { - continue; - } - $this->_after[] = $closure; - } - } + /** + * @param Closure|array|string $handler + * @throws Exception + */ + public function addAfter(Closure|string|array $handler) + { + if (!is_array($handler) || is_object($handler[0])) { + $handler = [$handler]; + } + foreach ($handler as $closure) { + if (in_array($closure, $this->_after)) { + continue; + } + $this->_after[] = $closure; + } + } - /** - * @param Closure|array|string $handler - * @throws Exception - */ - public function addLimits(Closure|string|array $handler) - { - if (!is_array($handler) || is_object($handler[0])) { - $handler = [$handler]; - } - foreach ($handler as $closure) { - if (in_array($closure, $this->_limits)) { - continue; - } - $this->_limits[] = $closure; - } - } + /** + * @param Closure|array|string $handler + * @throws Exception + */ + public function addLimits(Closure|string|array $handler) + { + if (!is_array($handler) || is_object($handler[0])) { + $handler = [$handler]; + } + foreach ($handler as $closure) { + if (in_array($closure, $this->_limits)) { + continue; + } + $this->_limits[] = $closure; + } + } - /** - * @return string - * 错误信息 - */ - public function getError(): string - { - return $this->_error; - } + /** + * @return string + * 错误信息 + */ + public function getError(): string + { + return $this->_error; + } - /** - * @param Node $node - * @param string $field - * @return Node - */ - public function addChild(Node $node, string $field): Node - { - $field = (string)$field; - /** @var Node $oLod */ - $oLod = $this->childes[$field] ?? null; - if (!empty($oLod)) { - $node = $oLod; - } - $this->childes[$field] = $node; - return $this->childes[$field]; - } + /** + * @param Node $node + * @param string $field + * @return Node + */ + public function addChild(Node $node, string $field): Node + { + $field = (string)$field; + /** @var Node $oLod */ + $oLod = $this->childes[$field] ?? null; + if (!empty($oLod)) { + $node = $oLod; + } + $this->childes[$field] = $node; + return $this->childes[$field]; + } - /** - * @param string $search - * @return Node|null - */ - public function findNode(string $search): ?Node - { - if (empty($this->childes)) { - return null; - } + /** + * @param string $search + * @return Node|null + */ + public function findNode(string $search): ?Node + { + if (empty($this->childes)) { + return null; + } - if (isset($this->childes[$search])) { - return $this->childes[$search]; - } + if (isset($this->childes[$search])) { + return $this->childes[$search]; + } - $_searchMatch = '/<(\w+)?:(.+)?>/'; - foreach ($this->childes as $key => $val) { - if (preg_match($_searchMatch, (string)$key, $match)) { - Input()->addGetParam($match[1] ?? '--', $search); - return $this->childes[$key]; - } - } - return null; - } + $_searchMatch = '/<(\w+)?:(.+)?>/'; + foreach ($this->childes as $key => $val) { + if (preg_match($_searchMatch, (string)$key, $match)) { + Input()->addGetParam($match[1] ?? '--', $search); + return $this->childes[$key]; + } + } + return null; + } - /** - * @param string $alias - * @return $this - * 别称 - */ - public function alias(string $alias): static - { - $this->_alias = $alias; - return $this; - } + /** + * @param string $alias + * @return $this + * 别称 + */ + public function alias(string $alias): static + { + $this->_alias = $alias; + return $this; + } - /** - * @return string - */ - public function getAlias(): string - { - return $this->_alias; - } + /** + * @return string + */ + public function getAlias(): string + { + return $this->_alias; + } - /** - * @param Closure|array $class - * @return $this - */ - public function addMiddleware(Closure|array $class): static - { - if (empty($class)) return $this; - foreach ($class as $closure) { - if (in_array($closure, $this->middleware)) { - continue; - } - $this->middleware[] = $closure; - } - return $this; - } + /** + * @param Closure|array $class + * @return $this + */ + public function addMiddleware(Closure|array $class): static + { + if (empty($class)) return $this; + foreach ($class as $closure) { + if (in_array($closure, $this->middleware)) { + continue; + } + $this->middleware[] = $closure; + } + return $this; + } - /** - * @return array - */ - public function getMiddleWares(): array - { - return $this->middleware; - } + /** + * @return array + */ + public function getMiddleWares(): array + { + return $this->middleware; + } - /** - * @return mixed - * @throws Exception - */ - public function dispatch(): mixed - { - Context::setContext('dispatch-param', func_get_args()); - if (empty($this->callback)) { - return Json::to(404, $this->errorMsg()); - } - return $this->httpFilter(); - } + /** + * @return mixed + * @throws Exception + */ + public function dispatch(): mixed + { + Context::setContext('dispatch-param', func_get_args()); + if (empty($this->callback)) { + return Json::to(404, $this->errorMsg()); + } + return call_user_func($this->handler, \request()); + return $this->httpFilter(); + } - /** - * @return mixed - * @throws Exception - */ - private function httpFilter(): mixed - { - if ($this->handler instanceof Closure) { - return call_user_func($this->handler, \request()); - } else { - return $this->runValidator([\request()]); - } - } + /** + * @return mixed + * @throws Exception + */ + private function httpFilter(): mixed + { + if ($this->handler instanceof Closure) { + return call_user_func($this->handler, \request()); + } else { + return $this->runValidator([\request()]); + } + } - /** - * @param $dispatchParams - * @return mixed - * @throws Exception - */ - private function runValidator($dispatchParams): mixed - { - if (empty($this->rules) || !is_array($this->rules)) { - return call_user_func($this->callback, ...$dispatchParams); - } - /** @var HttpFilter $filter */ - $filter = Snowflake::app()->get('filter'); - $validator = $filter->check($this->rules); - if (!($validator instanceof Validator) || $validator->validation()) { - return call_user_func($this->callback, ...$dispatchParams); - } else { - return Json::to(5005, $validator->getError()); - } - } + /** + * @param $dispatchParams + * @return mixed + * @throws Exception + */ + private function runValidator($dispatchParams): mixed + { + if (empty($this->rules) || !is_array($this->rules)) { + return call_user_func($this->callback, ...$dispatchParams); + } + /** @var HttpFilter $filter */ + $filter = Snowflake::app()->get('filter'); + $validator = $filter->check($this->rules); + if (!($validator instanceof Validator) || $validator->validation()) { + return call_user_func($this->callback, ...$dispatchParams); + } else { + return Json::to(5005, $validator->getError()); + } + } - /** - * @return string - */ - private function errorMsg(): string - { - return $this->_error ?? 'Page not found.'; - } + /** + * @return string + */ + private function errorMsg(): string + { + return $this->_error ?? 'Page not found.'; + } } diff --git a/HttpServer/Route/Router.php b/HttpServer/Route/Router.php index 54507196..1a1afae1 100644 --- a/HttpServer/Route/Router.php +++ b/HttpServer/Route/Router.php @@ -540,8 +540,7 @@ class Router extends HttpService implements RouterInterface if (!($node = $this->find_path(\request()))) { return send(self::NOT_FOUND); } - $response = $node->dispatch(); - send($response, 200); + send(($response = $node->dispatch()), 200); if (!$node->hasAfter()) { return null; }