HttpClient
HttpClient выполняет HTTP-запросы через асинхронные TCP-соединения Localzet Server и возвращает HTTP-объекты PSR-7. Вокруг соединений есть пул, очередь по адресу назначения, обработчики результата и вариант ожидания через suspension event loop.
Основной класс — localzet\HTTP\Client; это не Psr\Http\Client\ClientInterface и не оболочка над curl_exec().
Подключение
Заголовок раздела «Подключение»composer config repositories.localzet-http vcs https://github.com/localzet/HttpClientcomposer require localzet/http:dev-mainМанифест требует PHP ^8.0, curl, JSON, Server ^4.2, localzet/psr7 ^3.0 и psr/http-message ^2.0. Фактический runtime должен удовлетворять всем зависимостям, а не только минимальному PHP верхнего пакета.
Клиенту нужен запущенный Server/event loop. Отсутствие success callback на Unix включает ожидание через Server::$globalEvent->getSuspension(). Обычный CLI-скрипт без loop не становится синхронным HTTP-клиентом автоматически.
Запрос с callbacks
Заголовок раздела «Запрос с callbacks»Внутри worker с работающим event loop:
use localzet\HTTP\Client;
$client = new Client();$client->get( 'http://127.0.0.1:8081/health', ['Accept' => 'application/json'], static function ($response): void { echo $response->getStatusCode(), PHP_EOL; echo (string) $response->getBody(), PHP_EOL; }, static function (Throwable $error): void { error_log($error->getMessage()); },);Пример предполагает ваш локальный тестовый upstream. Создавайте Client на срок жизни worker, если хотите повторно использовать пул. Не создавайте новый пул на каждый запрос без причины.
Success callback означает получение HTTP-ответа, не бизнес-успех. Проверяйте status code и содержимое ответа самостоятельно: код 404 или 500 не превращается автоматически в транспортное исключение.
Метод и данные
Заголовок раздела «Метод и данные»$client->post($url, ['name' => 'Example'], $headers, $success, $error);
$client->request($url, 'PUT', ['enabled' => 1], $headers, [ 'success' => $success, 'error' => $error,]);В request() аргумент $data имеет тип array. Для POST/PUT/PATCH/DELETE массив записывается в body и обычно преобразуется через http_build_query(). Для остальных методов данные становятся query-параметрами.
Простое выставление Content-Type: application/json не сериализует массив в JSON. Высокоуровневый request() не принимает произвольную строку body вместо массива. В низкоуровневом Client\Request есть write(), но его соединение, события и завершение — отдельный API, который нельзя подменять примером request($url, ['json' => ...]) из другой библиотеки.
Результат и body
Заголовок раздела «Результат и body»localzet\HTTP\Client\Response наследует PSR7 Response. Методы статуса и заголовков работают через базовый класс, но (string) $response переопределён и возвращает только body, не полную HTTP-строку.
getBody()->getContents() читает от текущей позиции. Для большого ответа не приводите всё body к строке без ограничения размера. Callback progress получает очередной кусок данных из обработчика ответа; это не подтверждение завершения загрузки.
Пул и ограничения
Заголовок раздела «Пул и ограничения»Пул группирует соединения по tcp://host:port, хранит idle/using и обрабатывает ожидающие запросы при освобождении соединения.
| Параметр конструктора | Default |
|---|---|
max_conn_per_addr | 128 |
keepalive_timeout | 15 секунд |
connect_timeout | 30 секунд |
timeout | 30 секунд |
Есть важное ограничение реализации: настройки объединяются через array_merge_recursive(). При переопределении существующего числового ключа вместо scalar может получиться массив, что меняет дальнейшие сравнения/таймауты. До исправления этой логики не считайте передачу новых значений корректным способом настройки лимитов.
Отдельного ограничения длины очереди или общего объёма накопленного body здесь нет. Число соединений на адрес не ограничивает само по себе память при большом количестве ожидающих запросов.
Redirect
Заголовок раздела «Redirect»При ответе с кодом 3xx и Location создаётся новый Request с разрешённым относительно старого URI адресом. Счётчик allow_redirects.max по умолчанию равен пяти.
Redirect сохраняет request options и body; автоматическая browser-политика смены метода и удаления чувствительных заголовков при переходе на другой host не задаётся как отдельный контракт. Проверяйте разрешённые назначения и не отправляйте секретные headers на произвольный redirect URL.
Параметры redirect также проходят recursive merge. Значение allow_redirects = false не является эквивалентом опции другой HTTP-библиотеки: код ожидает вложенный max.
ParallelClient
Заголовок раздела «ParallelClient»ParallelClient::push() и batch() складывают запросы, await() содержит механизм ожидания через suspension. Однако текущий await() вызывает request($url, $options), тогда как второй параметр реального request() — строковый HTTP-метод. Массив во втором аргументе приводит к TypeError.
Поэтому не используйте этот wrapper как готовую batch-интеграцию. Для независимых запросов регистрируйте обычные callback-запросы Client в работающем event loop и координируйте завершение в коде приложения.
Ошибки и безопасность назначения
Заголовок раздела «Ошибки и безопасность назначения»Невалидный URL без host, ошибки подключения, response parser и превышение redirect limit идут в error path. Если error callback задан, его вызов откладывается через Timer. Без success callback на Unix ошибка может быть выброшена в контексте ожидания; если success задан, а error отсутствует, deferError может завершиться без передачи ошибки приложению. Не полагайтесь на один try/catch вокруг callback-запроса как на обработку последующего сетевого отказа.
URL выбирает исходящее соединение от имени сервера. Ограничивайте scheme/host/port и итоговый DNS-адрес до постановки запроса, а также после redirect. Клиент не предоставляет готовую SSRF-policy. Наличие HTTPS-префикса выбирает SSL transport, но отдельной явно документированной policy сертификатов/CA в API Client нет — проверяйте контекст конкретной версии Server.
Исходный код · AGPL-3.0