前文讲到当收到申请后,swoft将swoole原生的Request及Response对象封装成适宜swoft框架外部调用的Swoft\Http\Message\Request以及Swoft\Http\Message\Response.
接下来,本章将追随办法$this->dispatcher->dispatch($psrRequest, $psrResponse)逐渐剖析申请到来后的框架的调度过程.

先看Swoft\Http\Server\HttpDispatcher的实现:

public function dispatch(...$params): void{     /**     * @var Request  $request     * @var Response $response     */ [$request, $response] = $params;     $response = $this->configResponse($response);     /* @var RequestHandler $requestHandler */     $requestHandler = Swoft::getBean(RequestHandler::class);     try {        //初始化中间件        $requestHandler->initialize($this->requestMiddlewares, $this->defaultMiddleware);                 // 创立新的HttpContext并设置到Context中         // 在业务逻辑中获取到的Context就是这里设置的HttpContext         // 前面附上此办法的源码调用         // Before request         $this->beforeRequest($request, $response);                  // 触发BEFORE_REQUEST事件         // Trigger before handle event         Swoft::trigger(HttpServerEvent::BEFORE_REQUEST, null, $request, $response);                  // 匹配路由,将路由信息绑定在新的Request对象上,返回         // Match router and handle         $request = $this->matchRouter($request);                  // 调用handle解决申请,实际上就是解决中间件         // 控制器的执行也是放在中间件中执行的         // Swoft\Http\Server\Middleware\DefaultMiddleware         $response = $requestHandler->handle($request);     } catch (Throwable $e) {         // 在解决申请时若发送异样会被零碎在此处捕捉         // 而后调用HttpErrorDispatcher去解决对应的异样         // 咱们在业务中注册的异样解决类就是在此处失去执行         /** @var HttpErrorDispatcher $errDispatcher */         $errDispatcher = Swoft::getSingleton(HttpErrorDispatcher::class);         // Handle request error         $response = $errDispatcher->run($e, $response);     }     try {         // 调用格式化解决对象来格式化失去的response         // Format response content type         $response = $this->acceptFormatter->format($response);                  // 触发AFTER_REQUEST事件         // Trigger after request         Swoft::trigger(HttpServerEvent::AFTER_REQUEST, null, $response);                  // 返回内容给客户端         // 触发协程COROUTINE_DEFER和COROUTINE_COMPLETE事件,前面附代码         // After request         $this->afterRequest($response);     } catch (Throwable $e) {         // 此步骤呈现谬误,则示意未能将内容失常返回给客户端         // 须要写入error级别的谬误,控制台会有error内容打印         // 如果是协程环境(request周期内就是协程环境)         // 还会写入日志         Error::log('response error=%s(%d) at %s:%d', $e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine());     }}

办法应用的是php中的动静参数传递形式,前文说过,此办法以后获取的request及response变量是Swoft\Http\Message\Request以及Swoft\Http\Message\Response的实例.

beforeRequest源码(创立HttpContext):

private function beforeRequest(Request $request, Response $response): void{     $httpContext = HttpContext::new($request, $response);     // Add log data     if ($this->logger->isEnable()) {         $data = [             'event' => SwooleEvent::REQUEST,             'uri' => $request->getRequestTarget(),             'requestTime' => $request->getRequestTime(),         ];         $httpContext->setMulti($data);     }     Context::set($httpContext);}

HttpContext::new源码(self::__instance()实际上是获取的bean对象,bean的注解是@Bean(scope=Bean::PROTOTYPE)):

public static function new(Request $request, Response $response): self{     $instance = self::__instance();     $instance->request = $request;     $instance->response = $response;     return $instance;}

路由匹配代码:

private function matchRouter(Request $request): Request{     $method = $request->getMethod();     $uriPath = $request->getUriPath();     /** @var Router $router */     $router = Swoft::getSingleton('httpRouter');     $result = $router->match($uriPath, $method);     // Save matched route data to request     $request = $request->withAttribute(Request::ROUTER_ATTRIBUTE, $result);     context()->setRequest($request);     return $request;}

afterRequest代码:

private function afterRequest(Response $response): void{     // 后附代码     $response->send();     // Defer     Swoft::trigger(SwoftEvent::COROUTINE_DEFER);     // Destroy     Swoft::trigger(SwoftEvent::COROUTINE_COMPLETE);}

send代码:

public function send(): void{     // 是否发送文件     // Is send file     if ($this->filePath) {         // 批改发送状态为true         $this->sent = true;         // 写入header         // Write Headers to co response         foreach ($this->getHeaders() as $key => $value) {             $headerLine = implode(';', $value);             if ($key !== ContentType::KEY) {                $this->coResponse->header($key, $headerLine);             }         }                  // Do send file         $this->coResponse->header(ContentType::KEY, $this->fileType);         // 发送文件         $this->coResponse->sendfile($this->filePath);         return;      }          // 格式化返回内容,并发送     // Prepare and send     $this->quickSend($this->prepare());}

quickSend代码,此办法次要性能是将Swoft的Response对象通过申请解决实现取得的业务数据从新设置回swoole原生的Response对象,并调用原生Response对象的end办法返回数据给客户端:

public function quickSend(Response $response = null): void{     $response = $response ?: $this;          // 获取swoole原生Response对象     // 后续的设置和返回都是通过原生Response对象实现     // Ensure coResponse is right     $coResponse = $response->getCoResponse();          // 设置返回的headers     // Write Headers to co response     foreach ($response->getHeaders() as $key => $value) {         $headerLine = implode(';', $value);         if ($key === ContentType::KEY) {            $headerLine .= '; charset=' . $response->getCharset();            $coResponse->header($key, $headerLine, $this->headerUcWords);         } else {            $coResponse->header($key, $headerLine, $this->headerUcWords);         }     }          // 设置返回的COOKIES     // Write cookies     foreach ($response->cookies as $n => $c) {        $coResponse->cookie($n, $c['value'], $c['expires'], $c['path'], $c['domain'], $c['secure'], $c['httpOnly']);     }          // 设置返回的状态码     // Set status code     $coResponse->status($response->getStatusCode());          // 获取返回的body     // Set body     $content = $response->getBody()->getContents();          // 调用swoole的Response对象的end办法,发送数据给客户端     $coResponse->end($content);          // 批改发送状态为true     // 此属性是在创立Response对象是初始化为false的     // Ensure sent     $this->sent = true;}

总结:

1.申请的业务逻辑是在零碎注册的Swoft\Http\Server\Middleware\DefaultMiddleware中间件中失去执行的.2.申请的业务逻辑是包裹在try/catch块中执行的,出现异常会调用零碎和用户注册的异样解决handler.  该handler会返回一个Response对象,失常执行的中间件返回的Response对象将会被抛弃.  这也是swoft业务逻辑中出现异常后,跨域中间件无奈失常设置header的起因.  对于此点的解决形式请参考自己之前的文章[swoft中跨域设置的问题](https://segmentfault.com/a/1190000038411563)3.swoft返回数据的形式是将业务返回的Swoft\Http\Message\Response上携带的像headers,cookies,body等内容从新设置回swoole原生Response对象上,而后调用原生Response对象返回业务数据.4.在执行完发送动作后,swoft会触发协程的deffer和finish事件,之后本次申请正式完结,以后申请协程的生命周期也完结了.