Игнорировать ошибку запроса из наблюдаемого

#angular #rxjs

#angular #rxjs

Вопрос:

У меня есть приложение Angular, которое использует GraphQL в качестве структуры API. Когда в серверной части выдается ошибка, запрос имеет статус 500, но все равно возвращает стандартный JSON (может содержать массив «errors»). Однако этот статус 500 вызывает ошибку в наблюдаемом, когда я только подписываюсь на него. Я хочу проигнорировать выданную ошибку и вместо этого просто проверить наличие массива ошибок в ответе. Мой первый подход:

 login(email: string, password: string) {
        this.loginGQL.watch({email, password}).valueChanges.subscribe(result => {
            
            if(!result.errors || result.errors.length === 0) {
                this.authData.next(result.data.login);
            } else {
                this.error.next(result.errors[0].message);
            }
        });
    }
  

Я попробовал этот подход, чтобы попытаться решить проблему:

 login(email: string, password: string) {
        this.loginGQL.fetch({email, password}).pipe(map(result => 
            result.data
        ), catchError(
            err => {
                console.log(err);
                return err.message;
            }
        )).subscribe(
            (finalResult: string | AuthData) => {
                if(typeof finalResult !== "string") {
                    this.authData.next(finalResult);
                } else {
                    console.log(finalResult);
                    this.error.next(finalResult);
                }
            }
        );
    }
  

Однако это не только отбрасывает ответ, но и сообщение об ошибке также каким-то образом разбивается на отдельные буквы. Не лучший опыт.

Каков был бы наилучший подход к этому? Заранее спасибо.

Ответ №1:

Вы правы в использовании catchError оператора, но одним из его требований является то, что он должен возвращать наблюдаемое. И поскольку вы возвращаетесь err.message , каждый символ строки выдается по отдельности. Вместо этого вы могли бы использовать of() функцию RxJS для возврата ошибки в виде next уведомления. Она будет отправлена на next обратный вызов подписки. Попробуйте следующее

 import { of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';

login(email: string, password: string) {
  this.loginGQL.fetch({ email, password }).pipe(
    map(result => result.data), 
    catchError(err => {
      console.log(err);
      return of(err);     // <-- you could also return the required array here
    })
  ).subscribe(
    (finalResult: string | AuthData) => {
      if (typeof finalResult !== "string") {
        this.authData.next(finalResult);
      } else {
        console.log(finalResult);
        this.error.next(finalResult);
      }
    }
  );
}
  

Комментарии:

1. Это решение не только кажется наиболее ортодоксальным в соответствии с лучшими практиками (я слышал о функции ‘of’ раньше, когда я проходил курс Angular, я так и не узнал, что именно она делает), но оно также работает почти без сбоев. Единственное изменение, которое я внес в код, это: « возврат (err.NetworkError.error.errors[0].message); « Это возвращает исходное сообщение с сервера вместо сообщения об ошибке, сгенерированного во внешнем интерфейсе. Спасибо!

Ответ №2:

Observable.subscribe() имеет пару перегрузок, которые обрабатывают сценарии ошибок. subscribe Метод принимает до 3 аргументов ( next , error , complete ). Мы можем использовать второй error аргумент для обработки, перехватывать исключение и обрабатывать его так, как мы хотим. Подробная информация

 login(email: string, password: string) {
        this.loginGQL.watch({email, password}).valueChanges.subscribe(result => {
            this.authData.next(result.data.login);
        }, errorResult => {
           if(errorResult.errors amp;amp; errorResult.errors.length > 0) {
             this.error.next(errorResult.errors[0].message);
           }
        });
    }
  

Обратите внимание, что я удалил if(!result.errors || result.errors.length === 0) условие из next аргумента функции. Если вызвана функция next или complete , то ошибка не была выдана. Я оставил обратное условию в error функции, поскольку я предпочитаю иметь «проверки работоспособности» в коде, чтобы предотвратить случайные ошибки нулевой ссылки.

Комментарии:

1. Как это решает его проблему?

2. Я в замешательстве. Как я понял, первоначальный вопрос заключается в том, что 500 вызывает ошибку при подписке, и они хотят знать, как игнорировать ошибку и проверять только массив ошибок в ответе. Этот ответ использует error аргумент для обработки любых ошибок из наблюдаемого и проверяет, используя обратную логику из первоначальной попытки.

Ответ №3:

Я думаю, вы могли бы попробовать что-то вроде этого:

 src$.pipe(
  catchError(err => {

    // throwing another error so that `retryWhen` will intercept it
    const sources = [throwError(err)];

    // send the `errors` array as a `next` notification
    err.status === 500 amp;amp; sources.unshift(of(err.errors))

    return concat(...sources);
  }),

  // make sure the subscription is keept alive after `500` errors
  retryWhen(errors => errors.pipe(filter(err => err.status === 500))),
)