PSR-18: HTTP Client
Интерфейс \Psr\Http\Client\ClientInterface содержит всего один метод для отправки HTTP-запроса:
interface ClientInterface
{
public function sendRequest(RequestInterface $request): ResponseInterface;
}
PSR требует создать и передать объект запроса типа RequestInterface и возвращает объект ответа типа ResponseInterface (описаны в PSR-7). Обработка ошибок реализуется на исключениях. В ядре интерфейсы PSR-7 реализованы в классах:
\Bitrix\Main\Web\Uri– URI;\Bitrix\Main\Web\Http\Request– запрос;\Bitrix\Main\Web\Http\Response– ответ;\Bitrix\Main\Web\Http\Stream– тело запроса/ответа;\Bitrix\Main\Web\Http\ClientException– исключение верхнего уровня;\Bitrix\Main\Web\Http\RequestException– ошибка запроса;\Bitrix\Main\Web\Http\NetworkException– сетевая ошибка.
Особенностью PSR-7 является использование потоков для тела запроса и ответа. Ниже пример отправки формы методом POST:
use Bitrix\Main\Web\HttpClient;
use Bitrix\Main\Web\Uri;
use Bitrix\Main\Web\Http\Request;
use Bitrix\Main\Web\Http\Method;
use Bitrix\Main\Web\Http\Stream;
//use Bitrix\Main\Web\Http\FormStream;
use Bitrix\Main\Web\Http\ClientException;
$http = new HttpClient([
'compress' => true,
]);
$data = [
"k1" => "v1",
"k2" => "v2",
];
$uri = new Uri('http://vm.vad/test.php');
// подготовка тела запроса
$body = new Stream('php://temp', 'r+');
$body->write(http_build_query($data, '', '&'));
// ИЛИ более простой способ (main 23.300.0)
// $body = new FormStream($data);
$request = new Request(Method::POST, $uri, [], $body);
try
{
$response = $http->sendRequest($request);
var_dump($response->getStatusCode());
var_dump($response->getHeaders());
var_dump((string)$response->getBody());
}
catch (ClientException $e)
{
var_dump($e->getMessage());
}
Рассмотрим более сложный пример, когда нужно передать файл методом POST:
use Bitrix\Main\Web\HttpClient;
use Bitrix\Main\Web\Uri;
use Bitrix\Main\Web\Http\Request;
use Bitrix\Main\Web\Http\Method;
use Bitrix\Main\Web\Http\MultipartStream;
use Bitrix\Main\Web\Http\ClientException;
$http = new HttpClient([
'compress' => true,
]);
$res = fopen("/home/bitrix/www/20190807_120929.jpg", 'r');
$data = [
"k1" => "v1",
"k2" => "v2",
"k3" => [
'resource' => $res,
'filename' => "pic.jpg",
],
];
$uri = new Uri('http://vm.vad/test.php');
$body = new MultipartStream($data);
$headers = [
'User-Agent' => 'bitrix',
'Content-type' => 'multipart/form-data; boundary=' . $body->getBoundary(),
];
$request = new Request(Method::POST, $uri, $headers, $body);
fclose($res);
try
{
$response = $http->sendRequest($request);
var_dump($response->getStatusCode());
var_dump($response->getHeaders());
var_dump((string)$response->getBody());
}
catch (ClientException $e)
{
var_dump($e->getMessage());
}
Обратите внимание, что ответ с редиректом будет возвращён как есть, без перехода по заголовку Location. PSR-18 считает, что ответы с кодом 30x ничем не отличаются от всех остальных. Пример обработки редиректа может выглядеть так:
use Bitrix\Main\Web\HttpClient;
use Bitrix\Main\Web\Uri;
use Bitrix\Main\Web\Http\Request;
use Bitrix\Main\Web\Http\Method;
use Bitrix\Main\Web\Http\ClientException;
$http = new HttpClient([
'compress' => true,
'disableSslVerification' => true,
]);
$uri = new Uri('http://1с-битрикс.рф/');
$request = new Request(Method::GET, $uri);
try
{
do
{
$response = $http->sendRequest($request);
if ($response->hasHeader('Location'))
{
$location = $response->getHeader('Location')[0];
var_dump($location);
$request = $request->withUri(new Uri($location));
}
}
while ($response->hasHeader('Location'));
// var_dump((string)$response->getBody());
}
catch (ClientException $e)
{
var_dump($e->getMessage());
}
/*
Распечатает:
string(37) "https://xn--1--clc2aam4begg.xn--p1ai/"
string(25) "https://www.1c-bitrix.ru/"
*/
Вместо вышеуказанного можно использовать старый способ:
use Bitrix\Main\Web\HttpClient;
$http = (new HttpClient())->disableSslVerification();
var_dump($http->get('http://1с-битрикс.рф/'));