Guzzle 6 — Обещания — Отлов исключений

Я не очень понимаю, как поймать исключение (переслать его) в обработчике onReject. Мне было интересно, может ли кто-нибудь указать мне правильное направление, как это сделать.

Я отправляю несколько асинхронных запросов, и когда один из них завершается с ошибкой «Обнаружено неперехваченное исключение — тип: GuzzleHttp\Exception\ClientException», он никогда не перехватывается.

Я прочитал:

Но неясно, почему следующее не работает. Насколько я понимаю, когда ClientException вызывается внутри onReject (RequestException), оно затем толкает его дальше к следующему onReject (ClientException) и правильно перехватывается.

Любая помощь будет оценена по достоинству.

$client = new GuzzleHttp\Client();

$promise = $client->requestAsync('POST', SOME_URL, [
  ... SOME_PARAMS ...
]);

$promise->then(
function (ResponseInterface $res) {
  //ok
},
function (RequestException $e) {
  //inside here throws a ClientException
}
)->then(null, function (ClientException $e) {
  //Why does it not get caught/forwarded to this error handler?
});

person Fermier    schedule 05.06.2016    source источник
comment
Вы на самом деле решили это? Я застрял в одном и том же, и это заставляет меня подозревать, что, возможно, асинхронные запросы на самом деле не асинхронны? Потому что исключение не должно вызываться при запуске вашего сегмента кода, который отправляет асинхронный запрос , потому что это асинхронно...   -  person Aarón Gutiérrez    schedule 07.06.2020


Ответы (2)


Согласно документации guzzle,

Если в обратном вызове $onRejected выдается исключение, последующие обратные вызовы $onRejected вызываются с выброшенным исключением в качестве причины.

Итак, это должно работать:

$promise
->then(
    function (ResponseInterface $res) {
        // this will be called when the promise resolves
        return $someVal;
    },
    function (RequestException $e) {
        // this will be called when the promise resolving failed
        // if you want this to bubble down further the then-line, just re-throw:
        throw $e;
    }
)
->then(
    function ($someVal) {

    },
    function (RequestException $e) {
        // now the above thrown Exception should be passed in here
    });
person lkoell    schedule 28.11.2017
comment
Это правильный ответ, и он должен быть отмечен как решение! - person MAZux; 28.08.2020

Пожирание обещаний follow Promises/A+ стандартный. Поэтому мы можем положиться на официальное описание, чтобы понять интересующее вас поведение:

2.2.7.1. Если onFulfilled или onRejected возвращает значение x, запустите процедуру разрешения промисов [[Resolve]](promise2, x).

2.2.7.2. Если onFulfilled или onRejected вызывает исключение e, promise2 должно быть отклонено с e как причина.

И позже для случая 2.2.7.2:

2.3.2. Если x является обещанием, принять его состояние

Поэтому вы можете либо следовать решению, предложенному @lkoell, либо вернуть RejectedPromise из обратного вызова, что заставит последующее обещание принять состояние rejected.

$promiseA = $promise
    ->then(
        function (ResponseInterface $res) {
          //ok
        },
        function (RequestException $e) {
          //This will force $promiseB adopt $promiseC state and get rejected
          return $promiseC = new RejectedPromise($clientException);
        }
);
$promiseB = $promiseA->then(null, function (ClientException $e) {
          // There you will get rejection
});

Этот способ более гибкий, так как вы можете отклонить промис не только с исключением, но и по любой причине (кроме промиса).

person origaminal    schedule 28.12.2017