Compare commits

...

14 Commits

Author SHA1 Message Date
as2252258 d1adc532e1 eee 2026-07-03 16:08:07 +08:00
as2252258 ec22ac39a3 eee 2026-07-03 16:07:27 +08:00
as2252258 b96bd159d3 eee 2026-07-03 15:59:49 +08:00
as2252258 c31211a6fa eee 2026-07-03 15:53:55 +08:00
as2252258 45d8931267 eee 2026-07-03 15:06:12 +08:00
as2252258 7bcb789ed2 eee 2026-06-12 23:57:21 +08:00
as2252258 1d9d761798 eee 2025-12-31 00:19:30 +08:00
as2252258 22f425ceb7 ea 2025-11-28 11:43:24 +08:00
as2252258 a52610cf2a ea 2025-11-28 11:39:14 +08:00
as2252258 5697102a85 ea 2025-11-28 11:38:29 +08:00
as2252258 0c0a2fadd5 ea 2025-11-28 11:37:09 +08:00
as2252258 5061a17342 ea 2025-11-28 11:30:07 +08:00
as2252258 9c1bc63f78 ea 2025-11-26 07:52:46 +08:00
as2252258 345af9e727 eee 2025-07-14 15:35:37 +08:00
7 changed files with 815 additions and 956 deletions
+29 -6
View File
@@ -2,6 +2,7 @@
namespace Kiri; namespace Kiri;
use Exception;
use Swoole\Coroutine; use Swoole\Coroutine;
@@ -15,11 +16,11 @@ class Client
private CoroutineClient|CurlClient $abstracts; private CoroutineClient|CurlClient $abstracts;
/** /**
* @param string $host * @param string $host
* @param int $port * @param int $port
* @param bool $isSsl * @param bool $isSsl
*/ */
public function __construct(string $host, int $port, bool $isSsl = false) public function __construct(string $host, int $port, bool $isSsl = false)
{ {
if (class_exists(Coroutine::class) && Coroutine::getCid() > -1) { if (class_exists(Coroutine::class) && Coroutine::getCid() > -1) {
@@ -32,7 +33,7 @@ class Client
/** /**
* @param string $name * @param string $name
* @param array $arguments * @param array $arguments
* @return mixed * @return mixed
*/ */
public function __call(string $name, array $arguments) public function __call(string $name, array $arguments)
@@ -40,4 +41,26 @@ class Client
return $this->abstracts->{$name}(...$arguments); return $this->abstracts->{$name}(...$arguments);
} }
/**
* @param string $name
* @return mixed
* @throws Exception
*/
public function __get(string $name)
{
// TODO: Implement __get() method.
$getter = 'get' . ucfirst($name);
if (method_exists($this, $getter)) {
return $this->$getter();
} else if (method_exists($this, $name)) {
return $this->$name();
} else if (property_exists($this, $name)) {
return $this->$name;
} else {
throw new Exception('Property|Method "' . $name . '" does not exist.');
}
}
} }
+568 -736
View File
File diff suppressed because it is too large Load Diff
+14 -15
View File
@@ -34,7 +34,7 @@ class CoroutineClient extends ClientAbstracts
$path = '/' . $path; $path = '/' . $path;
} }
$host = $this->getHost(); $host = $this->host;
if (!preg_match('/(\d{1,3}\.){3}\d{1,3}/', $host)) { if (!preg_match('/(\d{1,3}\.){3}\d{1,3}/', $host)) {
$this->withAddedHeader('Host', $host); $this->withAddedHeader('Host', $host);
} }
@@ -62,16 +62,15 @@ class CoroutineClient extends ClientAbstracts
private function coroutine(string $url, array|string $data = []): void private function coroutine(string $url, array|string $data = []): void
{ {
try { try {
$this->generate_client($this->getHost(), $this->isSSL()); $this->generate_client($this->host, $this->isSSL);
if ($this->client->statusCode < 0) { if ($this->client->statusCode < 0) {
throw new Exception($this->client->errMsg); throw new Exception($this->client->errMsg);
} }
$this->execute($url, $data); $this->execute($url, $data);
} catch (\Throwable $exception) { } catch (\Throwable $exception) {
$this->setStatusCode(-1); $this->statusCode = -1;
$this->setBody(jTraceEx($exception)); $this->body = json_encode(['code' => 500, 'message' => $exception->getMessage()]);
} }
} }
@@ -87,8 +86,8 @@ class CoroutineClient extends ClientAbstracts
if (in_array($this->client->getStatusCode(), [502, 404])) { if (in_array($this->client->getStatusCode(), [502, 404])) {
$this->retry($path, $data); $this->retry($path, $data);
} else { } else {
$this->setStatusCode($this->client->getStatusCode()); $this->statusCode = $this->client->getStatusCode();
$this->setBody($this->client->getBody()); $this->body = $this->client->getBody();
$this->setResponseHeader($this->client->headers); $this->setResponseHeader($this->client->headers);
} }
} }
@@ -106,8 +105,8 @@ class CoroutineClient extends ClientAbstracts
$this->execute($path, $data); $this->execute($path, $data);
} else { } else {
$this->setStatusCode($this->client->statusCode); $this->statusCode = $this->client->statusCode;
$this->setBody($this->client->errMsg); $this->body = $this->client->errMsg;
} }
} }
@@ -117,17 +116,17 @@ class CoroutineClient extends ClientAbstracts
*/ */
private function generate_client(string $host, bool $isHttps): void private function generate_client(string $host, bool $isHttps): void
{ {
if ($isHttps || $this->isSSL()) { if ($isHttps || $this->isSSL) {
$this->client = new SwowClient($host, 443, true); $this->client = new SwowClient($host, 443, true);
} else { } else {
$this->client = new SwowClient($host, $this->getPort(), false); $this->client = new SwowClient($host, $this->getPort(), false);
} }
$this->client->set($this->settings()); $this->client->set($this->settings());
if (!empty($this->getAgent())) { if (!empty($this->agent)) {
$this->withAddedHeader('User-Agent', $this->getAgent()); $this->withAddedHeader('User-Agent', $this->agent);
} }
$this->client->setHeaders($this->getHeader()); $this->client->setHeaders($this->header);
$this->client->setMethod(strtoupper($this->getMethod())); $this->client->setMethod(strtoupper($this->method));
} }
@@ -138,7 +137,7 @@ class CoroutineClient extends ClientAbstracts
*/ */
private function setParams(string $path, mixed $data): string private function setParams(string $path, mixed $data): string
{ {
$content = $this->getData(); $content = $this->_data;
if (!empty($content)) { if (!empty($content)) {
$this->client->setData($content); $this->client->setData($content);
} }
+191 -185
View File
@@ -6,219 +6,225 @@ namespace Kiri;
/** /**
* Class CurlClient * Class CurlClient
*
* @package Http\Handler\Client * @package Http\Handler\Client
*/ */
class CurlClient extends ClientAbstracts class CurlClient extends ClientAbstracts
{ {
/** /**
* @param string $method * @param string $method
* @param string $path * @param string $path
* @param array|string $params * @param array|string $params
* @return void *
*/ * @return void
public function request(string $method, string $path, array|string $params = []): void */
{ public function request(string $method, string $path, array|string $params = []): void
if (!str_starts_with($path, '/')) { {
$path = '/' . $path; if (!str_starts_with($path, '/')) {
} $path = '/' . $path;
if ($method == self::GET) { }
$path = $this->joinGetParams($path, $params); if ($method == self::GET) {
} $path = $this->joinGetParams($path, $params);
}
$this->getCurlHandler($path, $method, $params); $this->getCurlHandler($path, $method, $params);
$this->execute(); $this->execute();
} }
/** /**
* @param string $path * @param string $path
* @param string $method * @param string $method
* @param $params * @param $params
* @return void *
*/ * @return void
private function getCurlHandler(string $path, string $method, $params): void */
{ private function getCurlHandler(string $path, string $method, $params): void
$host = $this->isSSL() ? 'https://' . $this->getHost() : 'http://' . $this->getHost(); {
if ($this->getPort() != 443 && $this->getPort() != 80) { $host = $this->isSSL ? 'https://' . $this->host : 'http://' . $this->host;
$host .= ':' . $this->getPort(); if ($this->getPort() != 443 && $this->getPort() != 80) {
} $host .= ':' . $this->getPort();
$this->do(curl_init($host . $path), $host . $path, $method); }
if ($this->isSSL()) { $this->do(curl_init($host . $path), $host . $path, $method);
$this->curlHandlerSslSet(); if ($this->isSSL) {
} $this->curlHandlerSslSet();
$contents = $this->getData(); }
if (empty($params) && empty($contents)) { $contents = $this->_data;
return; if (empty($params) && empty($contents)) {
} return;
if (!empty($contents)) { }
curl_setopt($this->client, CURLOPT_POSTFIELDS, $contents); if (!empty($contents)) {
} else if ($method === self::UPLOAD) { curl_setopt($this->client, CURLOPT_POSTFIELDS, $contents);
curl_setopt($this->client, CURLOPT_POSTFIELDS, $params); } else if ($method === self::UPLOAD) {
} else if ($method === self::POST) { curl_setopt($this->client, CURLOPT_POSTFIELDS, $params);
if (is_array($params)) { } else if ($method === self::POST) {
$params = http_build_query($params); if (is_array($params)) {
} $params = http_build_query($params);
curl_setopt($this->client, CURLOPT_POSTFIELDS, $params); }
} curl_setopt($this->client, CURLOPT_POSTFIELDS, $params);
} }
}
/** /**
* @return void * @return void
* @throws * @throws
*/ */
private function curlHandlerSslSet(): void private function curlHandlerSslSet(): void
{ {
if (!empty($this->getSslKeyFile()) && file_exists($this->getSslKeyFile())) { if (!empty($this->ssl_key_file) && file_exists($this->ssl_key_file)) {
curl_setopt($this->client, CURLOPT_SSLKEY, $this->getSslKeyFile()); curl_setopt($this->client, CURLOPT_SSLKEY, $this->ssl_key_file);
} }
if (!empty($this->getSslCertFile()) && file_exists($this->getSslCertFile())) { if (!empty($this->ssl_cert_file) && file_exists($this->ssl_cert_file)) {
curl_setopt($this->client, CURLOPT_SSLCERT, $this->getSslCertFile()); curl_setopt($this->client, CURLOPT_SSLCERT, $this->ssl_cert_file);
} }
if (!empty($this->getCa()) && file_exists($this->getCa())) { if (!empty($this->ca) && file_exists($this->ca)) {
curl_setopt($this->client, CURLOPT_CAINFO, $this->getCa()); curl_setopt($this->client, CURLOPT_CAINFO, $this->ca);
} }
} }
/** /**
* @param mixed $resource * @param mixed $resource
* @param string $path * @param string $path
* @param string $method * @param string $method
* @return void *
*/ * @return void
private function do(mixed $resource, string $path, string $method): void */
{ private function do(mixed $resource, string $path, string $method): void
curl_setopt($resource, CURLOPT_URL, $path); {
curl_setopt($resource, CURLOPT_TIMEOUT, $this->getTimeout()); // 超时设置 curl_setopt($resource, CURLOPT_URL, $path);
curl_setopt($resource, CURLOPT_CONNECTTIMEOUT, $this->getConnectTimeout()); // 超时设置 curl_setopt($resource, CURLOPT_TIMEOUT, $this->timeout); // 超时设置
curl_setopt($resource, CURLOPT_HEADER, TRUE); curl_setopt($resource, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout); // 超时设置
curl_setopt($resource, CURLOPT_FAILONERROR, TRUE); curl_setopt($resource, CURLOPT_HEADER, TRUE);
curl_setopt($resource, CURLOPT_HTTPHEADER, $this->parseHeaderMat()); curl_setopt($resource, CURLOPT_FAILONERROR, TRUE);
if (defined('CURLOPT_SSL_FALSESTART')) { curl_setopt($resource, CURLOPT_HTTPHEADER, $this->parseHeaderMat());
curl_setopt($resource, CURLOPT_SSL_FALSESTART, TRUE); if (defined('CURLOPT_SSL_FALSESTART')) {
} curl_setopt($resource, CURLOPT_SSL_FALSESTART, TRUE);
curl_setopt($resource, CURLOPT_FORBID_REUSE, FALSE); }
curl_setopt($resource, CURLOPT_FRESH_CONNECT, FALSE); curl_setopt($resource, CURLOPT_FORBID_REUSE, FALSE);
if (!empty($this->getAgent())) { curl_setopt($resource, CURLOPT_FRESH_CONNECT, FALSE);
curl_setopt($resource, CURLOPT_USERAGENT, $this->getAgent()); if (!empty($this->agent)) {
} curl_setopt($resource, CURLOPT_USERAGENT, $this->agent);
curl_setopt($resource, CURLOPT_NOBODY, FALSE); }
curl_setopt($resource, CURLOPT_RETURNTRANSFER, TRUE);//返回内容 curl_setopt($resource, CURLOPT_NOBODY, FALSE);
curl_setopt($resource, CURLOPT_FOLLOWLOCATION, TRUE);// 跟踪重定向 curl_setopt($resource, CURLOPT_RETURNTRANSFER, TRUE);//返回内容
curl_setopt($resource, CURLOPT_ENCODING, 'gzip,deflate'); curl_setopt($resource, CURLOPT_FOLLOWLOCATION, TRUE);// 跟踪重定向
if ($method === self::POST || $method == self::UPLOAD) { curl_setopt($resource, CURLOPT_ENCODING, 'gzip,deflate');
curl_setopt($resource, CURLOPT_POST, 1); if ($method === self::POST || $method == self::UPLOAD) {
} curl_setopt($resource, CURLOPT_POST, 1);
[$proxy, $port] = [$this->getProxyHost(), $this->getProxyPort()]; }
if (!empty($proxy) && $port > 0) { [$proxy, $port] = [$this->proxyHost, $this->proxyPort];
curl_setopt($resource, CURLOPT_PROXYPORT, $port); if (!empty($proxy) && $port > 0) {
curl_setopt($resource, CURLOPT_PROXY, $proxy); curl_setopt($resource, CURLOPT_PROXYPORT, $port);
} curl_setopt($resource, CURLOPT_PROXY, $proxy);
curl_setopt($resource, CURLOPT_CUSTOMREQUEST, strtoupper($method)); }
$this->client = $resource; curl_setopt($resource, CURLOPT_CUSTOMREQUEST, strtoupper($method));
if (!empty($this->caPath)) { $this->client = $resource;
curl_setopt($this->client, CURLOPT_CAINFO, $this->caPath); if (!empty($this->caPath)) {
} curl_setopt($this->client, CURLOPT_CAINFO, $this->caPath);
} }
}
/** /**
* @var string * @var string
*/ */
private string $caPath = ''; private string $caPath = '';
/** /**
* @param string $path * @param string $path
* @return $this *
*/ * @return $this
public function withCAInfo(string $path): static */
{ public function withCAInfo(string $path): static
$this->caPath = $path; {
return $this; $this->caPath = $path;
} return $this;
}
/** /**
* @throws * @throws
*/ */
private function execute(): void private function execute(): void
{ {
$output = curl_exec($this->client); $output = curl_exec($this->client);
if ($output !== FALSE) { if ($output !== FALSE) {
$this->explode($output); $this->explode($output);
} else { } else {
$this->setStatusCode(curl_errno($this->client)); $this->statusCode = curl_errno($this->client);
$this->setBody(curl_error($this->client)); $this->body = curl_error($this->client);
} }
} $this->close();
}
/** /**
* @return void * @return void
* @throws * @throws
*/ */
private function retry(): void private function retry(): void
{ {
if (($this->num += 1) <= $this->retryNum) { if (($this->num += 1) <= $this->retryNum) {
sleep($this->retryTimeout); sleep($this->retryTimeout);
$this->execute(); $this->execute();
} else { } else {
$this->setStatusCode(curl_errno($this->client)); $this->statusCode = curl_errno($this->client);
$this->setBody(curl_error($this->client)); $this->body = curl_error($this->client);
} }
} }
/** /**
* *
*/ */
public function close(): void public function close(): void
{ {
curl_close($this->client); if (PHP_VERSION < '8.0') {
} curl_close($this->client);
}
}
/** /**
* @param string $output * @param string $output
* @return void *
* @throws * @return void
*/ * @throws
private function explode(string $output): void */
{ private function explode(string $output): void
[$header, $body] = explode("\r\n\r\n", $output, 2); {
if ($header == 'HTTP/1.1 100 Continue') { // 获取 HTTP 状态码
[$header, $body] = explode("\r\n\r\n", $body, 2); $statusCode = +curl_getinfo($this->client, CURLINFO_HTTP_CODE);
}
$header = explode("\r\n", $header); // 获取 header 的大小(不包括最后的 \r\n\r\n 分隔符)
$status = explode(' ', array_shift($header)); $headerSize = curl_getinfo($this->client, CURLINFO_HEADER_SIZE);
$header = substr($output, 0, $headerSize);
$statusCode = intval($status[1]); if (in_array($statusCode, [502, 404])) {
if (in_array($statusCode, [502, 404])) { $this->retry();
$this->retry(); } else {
} else { $this->statusCode = $statusCode;
$this->setStatusCode($statusCode); $this->body = substr($output, $headerSize);
$this->setBody($body); $this->setResponseHeader(explode("\r\n", $header));
$this->setResponseHeader($header); }
} }
}
/** /**
* @return array * @return array
*/ */
private function parseHeaderMat(): array private function parseHeaderMat(): array
{ {
$headers = []; $headers = [];
foreach ($this->getHeader() as $key => $val) { foreach ($this->header as $key => $val) {
$headers[$key] = $key . ': ' . $val; $headers[$key] = $key . ': ' . $val;
} }
return array_values($headers); return array_values($headers);
} }
} }
+3 -4
View File
@@ -172,8 +172,7 @@ interface IClient
public function withContentType(string $contentType): static; public function withContentType(string $contentType): static;
/** public null|string $body {
* @return mixed get;
*/ }
public function getBody(): mixed;
} }
+9 -9
View File
@@ -11,16 +11,16 @@ trait TSwooleClient
*/ */
private function settings(): array private function settings(): array
{ {
$sslCert = $this->getSslCertFile(); $sslCert = $this->ssl_cert_file;
$sslKey = $this->getSslKeyFile(); $sslKey = $this->ssl_key_file;
$sslCa = $this->getCa(); $sslCa = $this->ca;
$params = []; $params = [];
if ($this->getConnectTimeout() > 0) { if ($this->connect_timeout > 0) {
$params['timeout'] = $this->getConnectTimeout(); $params['timeout'] = $this->connect_timeout;
} }
[$proxy, $port] = [$this->getProxyHost(), $this->getProxyPort()]; [$proxy, $port] = [$this->proxyHost, $this->proxyPort];
if (!empty($proxy) && $port > 0) { if (!empty($proxy) && $port > 0) {
$params['http_proxy_host'] = $proxy; $params['http_proxy_host'] = $proxy;
$params['http_proxy_port'] = $port; $params['http_proxy_port'] = $port;
@@ -29,9 +29,9 @@ trait TSwooleClient
return $params; return $params;
} }
$params['ssl_host_name'] = $this->getHost(); $params['ssl_host_name'] = $this->host;
$params['ssl_cert_file'] = $this->getSslCertFile(); $params['ssl_cert_file'] = $this->ssl_cert_file;
$params['ssl_key_file'] = $this->getSslKeyFile(); $params['ssl_key_file'] = $this->ssl_key_file;
$params['ssl_verify_peer'] = TRUE; $params['ssl_verify_peer'] = TRUE;
$params['ssl_cafile'] = $sslCa; $params['ssl_cafile'] = $sslCa;
+1 -1
View File
@@ -9,7 +9,7 @@
], ],
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": ">=8.0", "php": ">=8.5",
"ext-json": "*", "ext-json": "*",
"ext-swoole": "*" "ext-swoole": "*"
}, },