withMethod($method) ->coroutine( $this->matchHost($path), $this->paramEncode($params) ); } /** * @param $path * @return $this */ public function withCAInfo($path): static { return $this; } /** * @param $url * @param array|string $data * @throws Exception 使用swoole协程方式请求 */ private function coroutine($url, array|string $data = []): void { try { $this->generate_client($data, ...$url); } catch (\Throwable $exception) { Kiri::getDi()->get(Logger::class)->error('rpc', [$exception]); $this->setStatusCode(-1); $this->setBody(jTraceEx($exception)); } } /** * @param $data * @param $host * @param $isHttps * @param $path * @throws Exception */ private function generate_client($data, $host, $isHttps, $path): void { $this->client = new SwowClient(SWOOLE_TCP, FALSE); $this->client->set(array_merge($this->settings(), ['open_http_protocol' => true])); if (!$this->client->connect($host, $this->getPort())) { throw new Exception('链接失败'); } if ($isHttps || $this->isSSL()) $this->client->enableSSL(); if (!empty($this->getAgent())) { $this->withAddedHeader('User-Agent', $this->getAgent()); } $path = $this->setParams($path, $data); $this->withAddedHeader('Accept', ' text/html,application/xhtml+xml,application/json,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'); // $this->withAddedHeader('Accept-Encoding', 'gzip'); $this->withAddedHeader('Content-Length', $this->getData()->getSize()); $this->execute($path, $this->getData()->getContents()); } /** * @param string $path * @param string $content * @return void * @throws ConfigException */ private function execute(string $path, string $content) { $array = $this->_parseHeaders($path); if ($this->client->send(implode("\r\n", $array) . "\r\n\r\n" . $content)) { $receive = ''; while ($tmp = $this->client->recv()) { $receive .= $tmp; } Kiri::getDi()->get(Logger::class)->debug($receive); [$header, $body] = explode("\r\n\r\n", $receive); $header = explode("\r\n", $header); $status = array_shift($header); $this->setStatusCode(intval(explode(' ', $status)[1])); $this->parseResponseHeaders($header); $this->setBody($body); } } /** * @param string $path * @return array */ #[Pure] private function _parseHeaders(string $path): array { $array = []; $array[] = strtoupper($this->getMethod()) . ' ' . $path . ' HTTP/1.1'; if (!empty($this->getHeader())) { foreach ($this->getHeader() as $key => $value) { $array[] = sprintf('%s: %s', $key, $value); } } return $array; } /** * @param $client * @param $string * @return mixed */ private function waite(&$client, $string): mixed { $tmp = $client->recv(); if (!empty($tmp)) { return $this->waite($client, $string . $tmp); } return $string; } private function chunked() { } /** * @param array $headers * @return void */ private function parseResponseHeaders(array $headers) { $array = []; foreach ($headers as $header) { [$key, $value] = explode(': ', $header); $array[$key] = trim($value); } $this->setResponseHeader($array); } /** * @param $path * @param $data * @return string */ private function setParams($path, $data): string { if ($this->isGet()) { if (!empty($data)) $path .= '?' . $data; } else { $data = $this->mergeParams($data); if (!empty($data)) { $this->withBody(new Stream($data)); } } return $path; } /** * */ public function close(): void { /** @var SwowClient $client */ $client = $this->client; if (!$client || !$client->isConnected()) { return; } $client->close(); } }