[PHP] HTTP-клиент на стероидах
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Бывает так, что в проект не хочется тащить мощный и тяжелый HTTP-клиент, а хочется взять что-то легкое, но его функционала не достаточно. Для решения таких компромиссов у меня есть небольшие классы декораторы, которые я опубликовал на всеобщее обозрение под лицензией MIT.Смена версии протоколаК нам пришёл HTTP/2, но не каждый сервер, как и не каждый клиент его поддерживает. Если попробовать отправить запрос, принудительно указав версию протокола 2, можно получить от сервера ошибку 505 HTTP Version Not Supported. Пакет webclient/ext-protocol-version решает эту, возможно надуманную, проблему. При получении ответа 505 клиент повторит запрос, но уже с версией протокола, указанной в ответе сервера.
<?php
use Webclient\Extension\ProtocolVersion\Client;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
/**
* @var ClientInterface $client Ваш PSR-18 совместимый HTTP Client.
*/
$http = new Client($client);
/** @var RequestInterface $request */
$response = $http->sendRequest($request);
РедиректыОчень редко, но встречается, когда клиент не умеет следовать редиректам при ответе с кодом 3xx. В этом случае поможет пакет webclient/ext-redirect. Тут всё элементарно, Передаём в конструктор наш клиент и максимальное количество допустимых редиректов на один запрос.
<?php
use Webclient\Extension\Redirect\Client;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
/**
* @var ClientInterface $client Ваш PSR-18 совместимый HTTP Client.
* @var int $maxRedirects Максимальное количество допустимых редиректов.
*/
$http = new Client($client, $maxRedirects);
/** @var RequestInterface $request */
$response = $http->sendRequest($request);
ЛогированиеИногда нам необходимо логировать запросы и ответы. Пакет webclient/ext-log позволяет настроить логирование так, как этого требует проект. Помимо клиента, вам понадобится PSR-3 совместимый логгер. Для формирования строки лога используется интерфейс Webclient\Extension\Log\Formatter\Formatter, а для формирования ID запроса (для поиска в логах пары запрос-ответ) - Webclient\Extension\Log\IdGenerator\IdGenerator. По одной реализации этих интерфейсов поставляется из коробки:
- Webclient\Extension\Log\IdGenerator\UniqueIdGenerator - элементарный генератор на основе uniqid()
- Webclient\Extension\Log\Formatter\RawHttpFormatter - логирование запросов и ответов в виде RAW-текста.
<?php
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Webclient\Extension\Log\Client;
use Webclient\Extension\Log\Formatter\Formatter;
use Webclient\Extension\Log\IdGenerator\IdGenerator;
/**
* @var ClientInterface $client Ваш PSR-18 совместимый HTTP Client.
* @var LoggerInterface $logger Ваш PSR-3 совместимый логгер.
* @var IdGenerator|null $idGenerator Ваш ID-генератор.
* При передаче null будет использоваться
* Webclient\Extension\Log\IdGenerator\UniqueIdGenerator.
* @var Formatter|null $formatter Ваш форматировщик лога.
* При передаче null будет использоваться
* Webclient\Extension\Log\Formatter\RawHttpFormatter.
*/
$http = new Client(
$client,
$logger,
$idGenerator,
$formatter,
LogLevel::INFO, // Уровень логирования запросов
LogLevel::INFO, // Уровень логирования информационных ответов (Коды 1xx)
LogLevel::INFO, // Уровень логирования успешных ответов (Коды 2xx)
LogLevel::INFO, // Уровень лоигрования ответов с редиректом (Коды 3xx)
LogLevel::ERROR, // Уровень логирования ответов об ошибках клиента (Коды 4xx)
LogLevel::ERROR, // Уровень логирования ответов об ошибках сервера (Коды 5xx)
LogLevel::WARNING // Уровень логирования исключений HTTP клиента
);
/** @var RequestInterface $request */
$response = $http->sendRequest($request);
КукиБывают проекты, в которых не достаточно просто отправить запрос и получить ответ. Иногда нужно поддерживать сессию (ну или ещё что-то). Чтобы добавить вашему клиенту поддержку печенек, нужно отнаследоваться от абстрактного класса Webclient\Extension\Cookie\Cookie\Storage из пакета webclient/ext-cookie, либо воспользоваться одной из поставляемых с пакетом реализацией:
- Webclient\Extension\Cookie\Cookie\ArrayStorage - держит куки в памяти. Слетает после завершения скрипта;
- Webclient\Extension\Cookie\Cookie\NetscapeCookieFile - хранит куки в файле в соответствии с форматом Netscape.
<?php
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Webclient\Extension\Cookie\Client;
use Webclient\Extension\Cookie\Cookie\Storage;
/**
* @var ClientInterface $client Ваш PSR-18 совместимый HTTP Client.
* @var Storage $storage Хранилище куков.
* Вы можете отнаследоваться от этого класса для реализации своего хранилища.
*/
$http = new Client($client, $storage);
/** @var RequestInterface $request */
$response = $http->sendRequest($request);
КэшированиеО кэшировании, его плюсах и минусах сказано уже много. Если вам хочется разгрузить какой-то из своих редко обновляемых микросервисов (и нагрузить кэш), поможет пакет webclient/ext-cache. Чтобы завернуть в него свой клиент, вам понадобится реализация Psr\SimpleCache\CacheInterface из PSR-6, Psr\Http\Message\ResponseFactoryInterface и Psr\Http\Message\StreamFactoryInterface из PSR-18.Кэширование происходит на основе соответствующих заголовков HTTP-запросов и ответов.
<?php
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\SimpleCache\CacheInterface;
use Webclient\Extension\Cache\Client;
/**
* @var ClientInterface $client Ваш PSR-18 совместимый HTTP Client.
* @var CacheInterface $cache Ваш PSR-6 совместимый кэш.
* @var ResponseFactoryInterface $responseFactory
* Ваша PSR-17 совместимая фабрика ответов.
* @var StreamFactoryInterface $streamFactory
* Ваша PSR-17 совместимая фабрика потоков.
* @var string Строка, уникальная для приватного кэша (например, ID сессии).
*/
$http = new Client(
$client,
$cache,
$responseFactory,
$streamFactory,
$privateKey
);
/** @var RequestInterface $request */
$response = $http->sendRequest($request);
На этом расширения для клиентов заканчиваются, но статья продолжается. У меня есть ещё парочка инструментов, которые могут кому-то облегчить жизнь.Создание запросов с файламиКак известно, в PSR-7 есть два вида запросов - обычный запрос и серверный запрос. Они оба реализуют интерфейс Psr\Http\Message\RequestInterface (Psr\Http\Message\ServerRequestInterface его расширяет). При отправке файлов на сервер мы не можем просто взять серверный запрос, выполнить его метод withUploadedFiles($files) и передать полученный объект в HTTP-клиент. Для того, чтобы клиент корректно отправил запрос с файлами, эти файлы должны быть записаны в поток тела запроса. Библиотека webclient/helper-form предназначена для упрощения создания таких запросов. Для работы вам понадобятся реализации интерфейсов Psr\Http\Message\ResponseFactoryInterface и Psr\Http\Message\StreamFactoryInterface.фейковый клиентВ проектах бывает необходимость запросов к сервисам, которые не желательно дергать лишний раз (например, платные API), но код, использующий такие обращения, тестировать нужно.Для такого тестирования можно воспользоваться webclient/fake-http-client, который является реализацией Psr\Http\Client\ClientInterface, но под капотом вместо запроса к серверу вызывает Psr\Http\Server\RequestHandlerInterface из PSR-15 (преобразовав при необходимости Psr\Http\Message\RequestInterface в Psr\Http\Message\ServerRequestInterface). Реализация Psr\Http\Server\RequestHandlerInterface остаётся за вами - эмулируйте поведение, как вам нужно для тестирования.
<?php
use Webclient\Fake\Client;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
/**
* @var RequestHandlerInterface $handler Ваш обработчик запроса.
* @var array $serverParams Параметры сервера, которые будут добавлены
* при преобразовании из Psr\Http\Message\RequestInterface в
* Psr\Http\Message\ServerRequestInterface.
*/
$client = new Client($handler, $serverParams);
/**
* @var RequestInterface $request Ваш HTTP-запрос
*/
$response = $client->sendRequest($request);
Если вы передаете объект Psr\Http\Message\ServerRequestInterface клиенту и хотите, чтобы обработчик получил его как есть, добавьте атрибут Webclient\Fake\Client::NOREPLACEATTRIBUTE (иначе будет создан новый объект запроса).
<?php
use Webclient\Fake\Client;
use Psr\Http\Server\RequestHandlerInterface;
/**
* @var Client $client.
* @var ServerRequestInterface $request.
*/
$request = $request->withAttribute(Client::NOREPLACEATTRIBUTE, true);
$response = $client->sendRequest($request);
Чтобы хоть чуть-чуть упростить вам написание обработчика, в пакете поставляется класс Webclient\Fake\Handler\SimpleRoutingHandler - обработчик с примитивным роутингом.
<?php
use Webclient\Fake\Client;
use Webclient\Fake\Handler\SimpleRoutingHandler;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
/**
* @var RequestHandlerInterface $notFoundHandler Обработчик запросов,
* для которых не нашлось роута.
* @var RequestHandlerInterface $entityCreatedHandler Обработчик запросов
* для эмуляции созания сущности (POST /entities).
* @var RequestHandlerInterface $entityHandler Обработчик запросов
* для получения сущности (GET /entities/1).
* @var RequestHandlerInterface $entityDeletedHandler обработчик запросов
* для удаления сущности (DELETE /entities/2).
* @var RequestInterface $errorRequest Запрос несуществующего URI (GET /users).
* @var RequestInterface $entityCreatingRequest Запрос создания
* сущности (POST /entities).
* @var RequestInterface $entityRequest Запрос получения
* сущности (GET /entities/1).
* @var RequestInterface $entityDeletingRequest Запрос удаления
* сущности (DELETE /entities/2).
*/
$handler = new SimpleRoutingHandler($notFoundHandler);
$handler
->route(['GET', 'HEAD'], '/entities/1', $entityHandler)
->route(['POST'], '/entities', $entityCreatedHandler)
->route(['DELETE'], '/entities/2', $entityDeletedHandler)
;
$client = new Client($handler);
$resp1 = $client->sendRequest($errorRequest); // Вернёт ошибку 404
$resp2 = $client->sendRequest($entityCreatingRequest); // Вернёт ответс кодом 201
$resp3 = $client->sendRequest($entityRequest); // Вернёт ответ с кодом 200
$resp4 = $client->sendRequest($entityDeletingRequest); // Вернёт ответ с кодом 204
Надеюсь, вы не зря потратили время на прочтение этой статьи и кому-то приглянутся предоставленные инструменты. Спасибо за внимание!
===========
Источник:
habr.com
===========
Похожие новости:
- [Разработка веб-сайтов, PHP] Использование HAProxy и Docker на машине разработчика при разработке сайтов
- [Сетевые технологии, CRM-системы, Системное администрирование, PHP, Asterisk] Разбираемся с FreePBX и интегрируем его с Битрикс24 и не только
- [PHP, Анализ и проектирование систем, Конференции, Микросервисы] 26 сентября приглашаем на оффлайн-митап HOT Backend&Web в Краснодаре
- [Oracle, PHP, PostgreSQL] Кто победит: человек — венец творения или обратный слэш?
- [1С-Битрикс, JavaScript, PHP] Меняем страницу просмотра элемента универсальных списков в коробочном Битрикс24
- [PHP, Программирование] Перечисления в PHP
- [Разработка веб-сайтов, PHP] Ты решил написать свой фреймворк. Стоило оно того?
- [Настройка Linux, Разработка веб-сайтов, PHP, JavaScript, Серверное администрирование] Перенос почты между серверами через интерфейс пользователя посредством IMAPSync
- [1С-Битрикс, PHP] «Только не „Битрикс“!». Почему не стоит игнорировать изучение этого фреймворка
- [PDF, PHP] Lorem Ipsum: пишем от руки
Теги для поиска: #_php, #_httpklient (http-клиент), #_psr18, #_dekoratory (декораторы), #_opensource, #_php
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:18
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Бывает так, что в проект не хочется тащить мощный и тяжелый HTTP-клиент, а хочется взять что-то легкое, но его функционала не достаточно. Для решения таких компромиссов у меня есть небольшие классы декораторы, которые я опубликовал на всеобщее обозрение под лицензией MIT.Смена версии протоколаК нам пришёл HTTP/2, но не каждый сервер, как и не каждый клиент его поддерживает. Если попробовать отправить запрос, принудительно указав версию протокола 2, можно получить от сервера ошибку 505 HTTP Version Not Supported. Пакет webclient/ext-protocol-version решает эту, возможно надуманную, проблему. При получении ответа 505 клиент повторит запрос, но уже с версией протокола, указанной в ответе сервера. <?php
use Webclient\Extension\ProtocolVersion\Client; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; /** * @var ClientInterface $client Ваш PSR-18 совместимый HTTP Client. */ $http = new Client($client); /** @var RequestInterface $request */ $response = $http->sendRequest($request); <?php
use Webclient\Extension\Redirect\Client; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; /** * @var ClientInterface $client Ваш PSR-18 совместимый HTTP Client. * @var int $maxRedirects Максимальное количество допустимых редиректов. */ $http = new Client($client, $maxRedirects); /** @var RequestInterface $request */ $response = $http->sendRequest($request);
<?php
use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Webclient\Extension\Log\Client; use Webclient\Extension\Log\Formatter\Formatter; use Webclient\Extension\Log\IdGenerator\IdGenerator; /** * @var ClientInterface $client Ваш PSR-18 совместимый HTTP Client. * @var LoggerInterface $logger Ваш PSR-3 совместимый логгер. * @var IdGenerator|null $idGenerator Ваш ID-генератор. * При передаче null будет использоваться * Webclient\Extension\Log\IdGenerator\UniqueIdGenerator. * @var Formatter|null $formatter Ваш форматировщик лога. * При передаче null будет использоваться * Webclient\Extension\Log\Formatter\RawHttpFormatter. */ $http = new Client( $client, $logger, $idGenerator, $formatter, LogLevel::INFO, // Уровень логирования запросов LogLevel::INFO, // Уровень логирования информационных ответов (Коды 1xx) LogLevel::INFO, // Уровень логирования успешных ответов (Коды 2xx) LogLevel::INFO, // Уровень лоигрования ответов с редиректом (Коды 3xx) LogLevel::ERROR, // Уровень логирования ответов об ошибках клиента (Коды 4xx) LogLevel::ERROR, // Уровень логирования ответов об ошибках сервера (Коды 5xx) LogLevel::WARNING // Уровень логирования исключений HTTP клиента ); /** @var RequestInterface $request */ $response = $http->sendRequest($request);
<?php
use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; use Webclient\Extension\Cookie\Client; use Webclient\Extension\Cookie\Cookie\Storage; /** * @var ClientInterface $client Ваш PSR-18 совместимый HTTP Client. * @var Storage $storage Хранилище куков. * Вы можете отнаследоваться от этого класса для реализации своего хранилища. */ $http = new Client($client, $storage); /** @var RequestInterface $request */ $response = $http->sendRequest($request); <?php
use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\StreamFactoryInterface; use Psr\SimpleCache\CacheInterface; use Webclient\Extension\Cache\Client; /** * @var ClientInterface $client Ваш PSR-18 совместимый HTTP Client. * @var CacheInterface $cache Ваш PSR-6 совместимый кэш. * @var ResponseFactoryInterface $responseFactory * Ваша PSR-17 совместимая фабрика ответов. * @var StreamFactoryInterface $streamFactory * Ваша PSR-17 совместимая фабрика потоков. * @var string Строка, уникальная для приватного кэша (например, ID сессии). */ $http = new Client( $client, $cache, $responseFactory, $streamFactory, $privateKey ); /** @var RequestInterface $request */ $response = $http->sendRequest($request); <?php
use Webclient\Fake\Client; use Psr\Http\Message\RequestInterface; use Psr\Http\Server\RequestHandlerInterface; /** * @var RequestHandlerInterface $handler Ваш обработчик запроса. * @var array $serverParams Параметры сервера, которые будут добавлены * при преобразовании из Psr\Http\Message\RequestInterface в * Psr\Http\Message\ServerRequestInterface. */ $client = new Client($handler, $serverParams); /** * @var RequestInterface $request Ваш HTTP-запрос */ $response = $client->sendRequest($request); <?php
use Webclient\Fake\Client; use Psr\Http\Server\RequestHandlerInterface; /** * @var Client $client. * @var ServerRequestInterface $request. */ $request = $request->withAttribute(Client::NOREPLACEATTRIBUTE, true); $response = $client->sendRequest($request); <?php
use Webclient\Fake\Client; use Webclient\Fake\Handler\SimpleRoutingHandler; use Psr\Http\Message\RequestInterface; use Psr\Http\Server\RequestHandlerInterface; /** * @var RequestHandlerInterface $notFoundHandler Обработчик запросов, * для которых не нашлось роута. * @var RequestHandlerInterface $entityCreatedHandler Обработчик запросов * для эмуляции созания сущности (POST /entities). * @var RequestHandlerInterface $entityHandler Обработчик запросов * для получения сущности (GET /entities/1). * @var RequestHandlerInterface $entityDeletedHandler обработчик запросов * для удаления сущности (DELETE /entities/2). * @var RequestInterface $errorRequest Запрос несуществующего URI (GET /users). * @var RequestInterface $entityCreatingRequest Запрос создания * сущности (POST /entities). * @var RequestInterface $entityRequest Запрос получения * сущности (GET /entities/1). * @var RequestInterface $entityDeletingRequest Запрос удаления * сущности (DELETE /entities/2). */ $handler = new SimpleRoutingHandler($notFoundHandler); $handler ->route(['GET', 'HEAD'], '/entities/1', $entityHandler) ->route(['POST'], '/entities', $entityCreatedHandler) ->route(['DELETE'], '/entities/2', $entityDeletedHandler) ; $client = new Client($handler); $resp1 = $client->sendRequest($errorRequest); // Вернёт ошибку 404 $resp2 = $client->sendRequest($entityCreatingRequest); // Вернёт ответс кодом 201 $resp3 = $client->sendRequest($entityRequest); // Вернёт ответ с кодом 200 $resp4 = $client->sendRequest($entityDeletingRequest); // Вернёт ответ с кодом 204 =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:18
Часовой пояс: UTC + 5