kiwilan/php-http-pool

PHP 包,包含易于使用的 GuzzleHttp 池包装器,用于并发请求。

0.3.4 2024-03-16 09:49 UTC

README

Banner with cards catalog picture in background and PHP XML Reader title

php version downloads license tests codecov

PHP 包,包含易于使用的 GuzzleHttp 池包装器,与 GuzzleHttp\PoolGuzzleHttp\Client 一起使用,以执行并发请求。

注意

我喜欢 GuzzleHttp\Pool,但我想构建一个包装器使其更容易使用,Laravel Http\Pool 很酷但对我来说不够灵活。因此,HttpPool 允许你发送一个 array 或请求的 Collection,并获取一个带有所有 GuzzleHttp 功能以及更多功能的 Collection<mixed, HttpPoolResponse>

比 Laravel Http 池更灵活,如果 Laravel Pool 对你来说很完美,请继续使用它。

功能

  • 🚚 与非常大的请求池一起工作:请求分块以避免内存峰值
  • 🗂️ 保留每个请求的标识符:易于将响应放入原始项(例如,在 Laravel 的 CollectionModel 中)
  • 📦 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 属性,这取决于您。

警告

如果属性是 privateprotected,您必须定义带有逻辑名称的获取器:例如 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\CollectionHttpPoolResponse

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() 方法获取响应。它返回一个 HttpPoolResponseCollection

注意

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)

正文

HttpPoolResponseBodyGuzzleHttp\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 了解最近更改的更多信息。

致谢

许可

MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件