乐趣区

关于php:Swoft的HttpServer启动及请求工作流程三Request及Response封装过程

上一回讲到给 Server 增加了 10 个 swoole 监听事件.
在增加完 swoole 的事件后, 框架调用 Swoft 的 trigger()办法触发了几种用户注册的生命周期事件.
接着框架调用 server 的 start()办法, 正式开始承受用户申请.
本章将从 onRequest 事件着手, 逐渐剖析 Swoole 原生的 Request 及 Response 封装成 Swoft 中应用的 Swoft\Http\Message\Request 和 Swoft\Http\Message\Response 的过程.

先看 onRequest 代码:

public function onRequest(Request $request, Response $response): void
{$psrRequest = ServerRequest::new($request);
    $psrResponse = ServerResponse::new($response);
    $this->dispatcher->dispatch($psrRequest, $psrResponse);
}

此办法是 swoole 的 onRequest 回调函数, 所以参数传进来的 Request 和 Response 别离对应的类型是 Swoole\Http\RequestSwoole\Http\Response.
能够看到, 在收到参数后, 框架干的第一件事就是调用 Swoft\Http\Message\RequestSwoft\Http\Message\Response的 new 办法, 生成与之对应的合乎 psr 标准的对象.
接着, 框架将新生成的 request 和 response 对象作为参数传递给调度函数, 由调度函数去执行具体的业务逻辑并返回后果给客户端.

实现细节之 (Swoft\Http\Message\Request::new):
此办法以及外面用到的 Uri::new 办法都是获取 PROTOTYPE 模式的 bean

public static function new(CoRequest $coRequest): self
{
     // 此处获取的 bean 是一个新的对象, 因为以后类的 bean 注解
     // 为 PROTOTYPE 模式
     //@Bean(name="httpRequest", scope=Bean::PROTOTYPE)
     /** @var Request $self */
     $self = BeanFactory::getBean('httpRequest');
     
     // Server params
     // 获取 Swoole 原生 Request 对象的 server 参数
     $serverParams = $coRequest->server;
     
     // 将 Swoole 原生 Request 对象中的 header 设置到新获取的 bean 对象上
     // Set headers
     $self->initializeHeaders($headers = $coRequest->header ?: []);
     
     // 设置申请形式
     $self->method = $serverParams['request_method'] ?? '';
     
     // 绑定原生 Request 对象到新的 bean 对象上
     $self->coRequest = $coRequest;
     
     // 设置 GET 申请参数
     $self->queryParams = $coRequest->get ?: [];
     
     // 设置 COOKIE
     $self->cookieParams = $coRequest->cookie ?: [];
     
     // 设置 SERVER 参数
     $self->serverParams = $serverParams;
     
     // 将申请的 URI 设置为 requestTarget
     $self->requestTarget = $serverParams['request_uri'] ?? '';
     
     // 设置 URI
     // Save
     $self->uriPath = $serverParams['request_uri'] ?? '';
     
     // 设置 QUERY_STRING
     $self->uriQuery = $serverParams['query_string'] ?? '';
     
     // 如果 URI 中还蕴含? 号, 阐明还须要解决
     if (strpos($self->uriPath, '?') !== false) {
         // Split
         $parts = explode('?', $self->uriPath, 2);
         $self->uriPath = $parts[0];
         $self->uriQuery = $parts[1] ?? $self->uriQuery;
     }
     
     // 调用 Uri 类结构 Uri 对象并绑定给新的 bean 对象
     /** @var Uri $uri */
     $self->uri = Uri::new('', ['host'=> $headers['host'] ??'',
         'path' => $self->uriPath,
         'query' => $self->uriQuery,
         'https' => $serverParams['https'] ?? '','http_host'=> $serverParams['http_host'] ??'',
         'server_name' => $serverParams['server_name'] ?? '','server_addr'=> $serverParams['server_addr'] ??'',
         'server_port' => $serverParams['server_port'] ?? '',
     ]);
     
     // 如果以后 headers 外面没有 host 数据, 则通过 Uri 对象去更新
     // 
     // Update host by Uri info
     if (!isset($headers['host'])) {$self->updateHostByUri();
     }
     return $self;
}

Uri::new 的实现:

public static function new(string $uri = '', array $params = []): self
{
     /** @var Uri $instance */
     $instance = Swoft::getBean(self::class);
     // Save some params
     $instance->params = $params;
     // Weak type check to also accept null until we can add scalar type hints
     if ($uri === '') {return $instance;}
     // If params is empty, padding defaults data
     if (!$params) {$instance->params = self::DEFAULT_PARAMS;}
     $parts = parse_url($uri);
     if ($parts === false) {throw new InvalidArgumentException("Unable to parse URI: $uri");
     }
     $instance->applyParts($parts);
     return $instance;
}

实现细节之 (Swoft\Http\Message\Response::new):
此办法依然是获取 PROTOTYPE 模式的 bean, 申请初期只是很单纯的设置了是否发送的状态以及绑定原生 Response 对象, 并未做过多设置.

public static function new(CoResponse $coResponse): self
{
     /** @var Response $self */
     $self = BeanFactory::getBean('httpResponse');
     // $self = bean('httpResponse');
     $self->sent = false;
     $self->coResponse = $coResponse;
     return $self;
}
退出移动版