kiwilan / php-http-pool
PHP 包,包含易于使用的 GuzzleHttp 池包装器,用于并发请求。
Requires
- php: ^8.1
- guzzlehttp/guzzle: ^7.7
- illuminate/support: ^10 || ^11.0
- symfony/console: ^6 || ^7
Requires (Dev)
- laravel/pint: ^1.2
- pestphp/pest: ^1.20
- spatie/ray: ^1.28
README
PHP 包,包含易于使用的 GuzzleHttp
池包装器,与 GuzzleHttp\Pool
和 GuzzleHttp\Client
一起使用,以执行并发请求。
注意
我喜欢 GuzzleHttp\Pool
,但我想构建一个包装器使其更容易使用,Laravel Http\Pool
很酷但对我来说不够灵活。因此,HttpPool
允许你发送一个 array
或请求的 Collection
,并获取一个带有所有 GuzzleHttp
功能以及更多功能的 Collection<mixed, HttpPoolResponse>
。
比 Laravel Http
池更灵活,如果 Laravel Pool 对你来说很完美,请继续使用它。
功能
- 🚚 与非常大的请求池一起工作:请求分块以避免内存峰值
- 🗂️ 保留每个请求的标识符:易于将响应放入原始项(例如,在 Laravel 的
Collection
的Model
中) - 📦
HttpPoolResponse
包装器,具有一些功能以提高 DX:原始 ID、正文、元数据... - 🏡 在
HttpPoolResponse
中保留原始GuzzleHttp
响应:你在家 - 🚨 允许处理内存峰值:如果你有很多请求
- 🗃️ 与简单的数组、关联数组、对象数组以及 Laravel
Collection
一起工作:只需定义获取标识符和 URL 的位置即可 - 💬 可选的控制台输出:如果您不想看到进度,可以禁用它
- 🚀 与任何 PHP 框架一起工作,
Illuminate\Support\Collection
是依赖项,但您可以在不使用 Laravel 的情况下使用它,在池执行后,如果您不想使用Collection
,则可用toArray()
方法
安装
您可以通过 composer 安装此包
composer require kiwilan/php-http-pool
使用方法
输入
当您想使用 HttpPool
时,您必须传递一个输入,它可以是:一个简单的数组、一个关联数组、一个 Laravel Collection
或一个对象数组。
使用简单数组
use Kiwilan\HttpPool\HttpPool; // Key is the identifier, value is the URL // Array could be associative or not $urls = [ 2 => 'https://jsonplaceholder.typicode.com/posts', 5 => 'https://jsonplaceholder.typicode.com/comments', 10 => 'https://jsonplaceholder.typicode.com/albums', 16 => 'https://jsonplaceholder.typicode.com/photos', 24 => 'https://jsonplaceholder.typicode.com/todos', ]; // Create a pool with an array of URLs and some options $pool = HttpPool::make($urls) ->setMaxCurlHandles(100) ->setMaxRedirects(10) ->setTimeout(30) ->setConcurrencyMaximum(5) ->setPoolLimit(250) ->setHeaders([ 'User-Agent' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', ]) ; // Get original requests converted for `HttpPool` $requests = $pool->getRequests(); $requestCount = $pool->getRequestCount(); // Execute pool $res = $pool->execute(); // Get responses $responses = $res->getResponses(); // Get responses as array $responsesArray = $res->toArray(); // Get only fullfilled responses $fullfilled = $res->getFullfilledResponses(); // Get only rejected responses $rejected = $res->getRejectedResponses(); // Counts $fullfilledCount = $res->getFullfilledCount(); $rejectedCount = $res->getRejectedCount(); // Get execution time $executionTime = $res->getExecutionTime(); // Get pool instance $pool = $res->getPool();
关联数组
警告
标识符和 URL 必须不是嵌套的。
use Kiwilan\HttpPool\HttpPool; $urls = [ [ 'uuid' => 100, 'name' => 'posts', 'api' => 'https://jsonplaceholder.typicode.com/posts', ], [ 'uuid' => 125, 'name' => 'comments', 'api' => 'https://jsonplaceholder.typicode.com/comments', ], ]; $res = HttpPool::make($urls) ->setIdentifierKey('uuid') // Default is 'id' ->setUrlKey('api') // Default is 'url' ->execute() ; $first = $res->getResponses()->first(); // HttpPoolResponse $first->getId(); // 100, 125
Laravel 模型
使用 Laravel 模型集合并发送请求 HttpPool
。这里 Book
是一个 Laravel 模型,我们假设 Book
有一个 id
属性和一个 google_book_api
属性。
use App\Models\Book; use Kiwilan\HttpPool\HttpPool; $books = Book::all(); // `Illuminate\Support\Collection` of `Book` $pool = HttpPool::make($books) ->setUrlKey('google_book_api') // Default is 'url' ->execute() ; $first = $pool->getResponses()->first(); // HttpPoolResponse $first->getId(); // 1, 2, 3... (Book ID)
对象数组
这里我们使用一个对象数组,我们假设每个对象都有一个 uuid
属性和一个 url
属性。您可以定义像 getUuid()
和 getUrl()
这样的获取器,或者您可以使用 public
属性,这取决于您。
警告
如果属性是 private
或 protected
,您必须定义带有逻辑名称的获取器:例如 getUuid()
和 getUrl()
。您也可以使用 uuid()
和 url()
作为获取器。但是,如果您创建一个获取器 getBookUuid()
,则它将不起作用。
use Kiwilan\HttpPool\HttpPool; $urls = [ new Book( uuid: 100, name: 'posts', url: 'https://jsonplaceholder.typicode.com/posts', ), new Book( uuid: 125, name: 'comments', url: 'https://jsonplaceholder.typicode.com/comments', ), ]; $res = HttpPool::make($urls) ->setIdentifierKey('uuid') // Default is 'id' ->execute() ; $first = $res->getResponses()->first(); // HttpPoolResponse $first->getId(); // 100, 125
执行
要执行池,您可以使用 execute()
方法。
use Kiwilan\HttpPool\HttpPool; $pool = HttpPool::make($urls); $res = $pool->execute();
execute()
方法返回一个 HttpPoolFullfilled
对象。您可以使用 getPool()
方法获取池。
use Kiwilan\HttpPool\HttpPool; $pool = HttpPool::make($urls); $res = $pool->execute(); $pool = $res->getPool();
在 HttpPoolFullfilled
对象中,您可以获取响应以及其他功能。所有方法 getResponses()
、getFullfilled()
和 getRejected()
都是 Illuminate\Support\Collection
的 HttpPoolResponse
。
use Kiwilan\HttpPool\HttpPool; $pool = HttpPool::make($urls); $res = $pool->execute(); // Get all responses (fullfilled and rejected) $responses = $res->getResponses(); // Get only fullfilled responses $fullfilled = $res->getFullfilled(); // Get only rejected responses $rejected = $res->getRejected(); // Get responses count $responsesCount = $res->getResponsesCount(); // Get fullfilled responses count $fullfilledCount = $res->getFullfilledCount(); // Get rejected responses count $rejectedCount = $res->getRejectedCount(); // Get execution time $executionTime = $res->getExecutionTime(); // Get if pool is failed $isFailed = $res->isFailed(); // Get errors $errors = $res->getErrors();
错误
要处理错误,您只需使用 HttpPool::make()
方法,错误将抛出异常。但如果您想防止错误,可以使用 throwErrors
参数。
use Kiwilan\HttpPool\HttpPool; $pool = HttpPool::make($urls, throwErrors: false);
所有错误都可以在池执行后通过 getErrors()
方法找到。
$res = $pool->execute(); $isFailed = $res->isFailed(); $errors = $res->getErrors();
响应
池执行后,您可以使用 getResponses()
方法获取响应。它返回一个 HttpPoolResponse
的 Collection
。
注意
getResponses
的第一个项目可能不是您发送的第一个请求。它取决于每个请求的响应时间。但您可以使用 getMetadata()->getRequest()
方法检索原始请求,定义一个 ID 来找到父项是最佳方式,您可以通过 getId()
方法检索它。
$responses = $res->getResponses(); $first = $responses->first(); // HttpPoolResponse $first->getId(); // Get original ID $first->getMetadata(); // Get HttpPoolResponseMetadata $first->getGuzzle(); // Get original GuzzleHttp\Psr7\Response $first->getBody(); // Get HttpPoolResponseBody $first->isSuccess(); // Get if response is success $first->isBodyAvailable(); // Get if response body exists
元数据
HttpPoolResponse
有一个 HttpPoolResponseMetadata
属性,它包含一些有用的数据。这里 $first
是一个 HttpPoolResponse
。
$metadata = $first->getMetadata(); $statusCode = $metadata->getStatusCode(); // 200, 404, 500... $status = $metadata->getStatus(); // Guzzle pool status: fullfilled, rejected $reason = $metadata->getReason(); // OK, Not Found, Internal Server Error... $isSuccess = $metadata->isSuccess(); // 200 <= $statusCode < 300 $isFailed = $metadata->isFailed(); // status code is not success $isJson = $metadata->isJson(); // is a valid JSON $isXml = $metadata->isXml(); // is a valid XML $server = $metadata->getServer(); // Server header $date = $metadata->getDate(); // Date header $contentType = $metadata->getContentType(); // Content-Type header $request = $metadata->getRequest(); // Original request $headers = $metadata->getHeaders(); // Original headers as array<string, string> $header = $metadata->getHeader('Content-Type'); // Extract header (safe method)
正文
HttpPoolResponseBody
是 GuzzleHttp\Psr7\Stream
的包装,包含一些有用的方法。这里 $first
是一个 HttpPoolResponse
。
$body = $first->getBody(); $isExists = $body->isExists(); // Get if body exists $contents = $body->getContents(); // Get body contents $json = $body->getJson(); // Get body as JSON $xml = $body->getXml(); // Get body as XML $isBinary = $body->isBinary(); // Get if body is binary $isJson = $body->isJson(); // Get if body is a valid JSON $isXml = $body->isXml(); // Get if body is a valid XML $isString = $body->isString(); // Get if body is a string $toArray = $body->toArray(); // Get body as array
高级
您可以使用一些高级选项来自定义您的池。
使用 URL 作为标识符以替换 ID。
HttpPool::make($urls) ->setUrlAsIdentifier();
启用控制台输出。
HttpPool::make($urls) ->allowPrintConsole();
内存峰值
处理内存峰值是可选的,但如果您有大量请求,您可以使用 allowMemoryPeak
来避免内存峰值。新的内存峰值将在 execute()
方法内设置。
默认情况下,内存峰值设置为 2G
,您可以通过第二个参数来更改它。
HttpPool::make($urls) ->allowMemoryPeak('2G');
测试
composer test
变更日志
请参阅 CHANGELOG 了解最近更改的更多信息。
致谢
- Guzzle 提供了出色的 HTTP 客户端
- Laravel 为
Illuminate\Support\Collection
- Symfony 为
symfony/console
- Spatie 为包骨架
- Ewilan Rivière
- 所有贡献者
许可
MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件。