Не отправляйте запросы через cURL вручную – используйте специализированную библиотеку, которая умеет работать с заголовками, кодировками, телом запроса и обработкой ошибок. Один из самых популярных инструментов – это клиент, построенный поверх PSR-7, который можно легко внедрить в любой проект на базе Composer.
Подключение производится в пару строк: создаётся объект клиента, затем вызывается метод, соответствующий нужному HTTP-методу. Важно указывать правильные параметры: base_uri, таймауты, заголовки, формат отправляемых данных. Особенно аккуратно стоит подходить к отправке JSON: большинство сервисов требует точного соответствия структуре схемы.
Обработка ошибок – не дополнительная опция, а необходимость. При работе с удалёнными сервисами возможны таймауты, проблемы с DNS, авторизацией или лимитами по количеству запросов. Ловите исключения, анализируйте статус-коды и содержимое ответа. Лучше предусмотреть все варианты заранее, чем получать пустой результат без объяснений.
При работе с токенами авторизации удобно использовать промежуточный слой, который добавляет нужные заголовки автоматически. Также можно создать обёртку над клиентом, чтобы повторно не писать код получения access token, если он истёк. Это особенно актуально для сервисов с OAuth 2.0.
Для тестирования подключений используйте мок-серверы и логгеры. Это позволит отладить запросы, не тратя лимиты реального сервиса, и видеть, что именно отправляется. Не забудьте отключать такие инструменты в проде, чтобы не засорять логи лишней информацией.
Настройка Guzzle для работы с авторизацией и токенами доступа
Сразу указывайте заголовок Authorization в параметрах запроса, если токен уже получен. Пример:
$client = new \GuzzleHttp\Client([
'headers' => [
'Authorization' => 'Bearer ' . $accessToken
]
]);
Для OAuth2 стоит автоматизировать получение и обновление токена. Используйте промежуточный слой – например, замыкание или кастомный middleware, который проверяет срок действия токена и обновляет его при необходимости:
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
$stack = HandlerStack::create();
$stack->push(Middleware::mapRequest(function ($request) use (&$accessToken) {
if (токен_просрочен($accessToken)) {
$accessToken = обновить_токен(); // логика обновления токена
}
return $request->withHeader('Authorization', 'Bearer ' . $accessToken);
}));
$client = new \GuzzleHttp\Client(['handler' => $stack]);
Если токен приходит в ответе при первом запросе, парсите JSON и сохраняйте токен для повторного использования:
$response = $client->post('https://example.com/token', [
'form_params' => [
'client_id' => '...',
'client_secret' => '...',
'grant_type' => 'client_credentials',
]
]);
$data = json_decode($response->getBody(), true);
$accessToken = $data['access_token'];
Не забывайте кэшировать токен, чтобы не обращаться к серверу лишний раз. Используйте любой доступный механизм: файл, Redis, БД – что быстрее под рукой.
Обработка ошибок при взаимодействии с нестабильными API-сервисами
Сначала настрой автоматическое повторение запросов при сбоях. Используй параметр retry
в связке с middleware-обработчиком. Это особенно помогает при временных ошибках вроде 502, 503 и 504.
Пример реализации через middleware
use GuzzleHttp\Middleware;
use GuzzleHttp\Exception\RequestException;
use Psr\Http\Message\RequestInterface;
$handlerStack = \GuzzleHttp\HandlerStack::create();
$maxRetries = 3;
$handlerStack->push(Middleware::retry(
function ($retries, RequestInterface $request, $response, RequestException $exception) use ($maxRetries) {
if ($retries >= $maxRetries) {
return false;
}
if ($response && in_array($response->getStatusCode(), [502, 503, 504])) {
return true;
}
if ($exception instanceof ConnectException) {
return true;
}
return false;
},
function ($retries) {
return 1000 * $retries;
}
));
Добавь логирование каждого сбоя. Это поможет быстрее разбираться в причинах ошибок и не гадать, что пошло не так.
Что ещё стоит учесть:
- Устанавливай таймаут не более 5–10 секунд. Зависшие соединения – частая причина залипаний в продакшене.
- Проверяй наличие ключей в ответе, прежде чем к ним обращаться. Даже при статусе 200 данные могут отсутствовать.
- Обрабатывай все исключения:
RequestException
,ConnectException
,ServerException
,ClientException
. Не лови их обобщённо – так теряется точность реакции.
И не забывай: API может возвращать странности – например, ошибку 200 с текстом «error» в теле. Всегда проверяй не только статус, но и структуру тела ответа.
Построение запросов с параметрами, заголовками и телом через Guzzle
Всегда задавай параметры явно: query – для строки запроса, form_params – для формы, json – для тела в формате JSON. Не путай их между собой, иначе сервер может вернуть ошибку 400 или интерпретировать данные неправильно.
Передача query-параметров
Если нужно отправить GET-запрос с параметрами, добавь ключ 'query'
в массив настроек:
$client->request('GET', 'https://example.com/data', [
'query' => [
'page' => 2,
'limit' => 50
]
]);
Добавление заголовков и тела
При работе с POST-запросами добавляй заголовки через 'headers'
, а тело – через 'json'
или 'form_params'
:
$client->request('POST', 'https://example.com/send', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/json'
],
'json' => [
'email' => '[email protected]',
'message' => 'Привет!'
]
]);
Если отправляешь форму (например, application/x-www-form-urlencoded), используй form_params
вместо json
. Не пиши оба ключа одновременно – будет конфликт.
Для отправки файлов подключай multipart
. Каждый элемент – массив с ключами name
, contents
, а при необходимости – filename
и headers
.
$client->request('POST', 'https://example.com/upload', [
'multipart' => [
[
'name' => 'file',
'contents' => fopen('/path/to/file.jpg', 'r'),
'filename' => 'photo.jpg'
]
]
]);
Не передавай заголовки вручную, если используешь json
или form_params
– библиотека сама добавляет нужный Content-Type
.