Как правильно throwError и в чем смысл различных ловушек ошибок в Angular HTTP

Я провел довольно много исследований, прежде чем решил опубликовать вопросы здесь. Мои знания о том, как Angular (или вообще) обрабатывает ошибку HTTP, очень туманны, поэтому я ищу некоторые разъяснения/предложения.

Для простоты предположим, что у меня есть API для отдыха GET http://example.com, который случайным образом возвращает {error: 'Error message'} или {data: 'Data is available'}, где error указывает на то, что что-то пошло не так (запрос выполнен успешно, но есть какая-то внутренняя ошибка), а data указывает на то, что все работает нормально.

Теперь, есть 2 вещи, которые, насколько я понимаю, нуждаются в обработке. Первое — это обработка при сбое запроса, например, сетевая ошибка, блокировка CORS и т. д., а второе — обработка успешного запроса, но посмотрите, error или data.

TL;DR: Как я могу преобразовать приведенный ниже jQuery в Angular?

Обычно с jQuery я бы сделал следующее:

$.get('http://example.com').done(data => {

    if ('error' in data) console.log('Request completed, but there is an error in the remote server');
    else console.log('Everything completed successfully');

).fail(error => {

    console.log('Error while requesting data', error);

});

Теперь в Angular все усложняется, и я, что бы я ни пытался, не могу выдать ошибку (все функции правильно импортированы):

//service.ts
    getStatus() {

        return this.http.get('https://test.com/')
        .pipe(
            map(data => {
                if ('error' in data) {
                    //I would like to throw an error that can be caught at subscribe(done, error) later
                    //But this rxjs won't throw anything, subscribe() will still resolve with done()
                    return throwError('Request completed, but there is an error in the remote server');
                }
                return data;
            }),
            tap(data => {
                //Process the data, should not be called if map() throwError()?
            },
            catchError(error => {
                //I assume this is where the HTTP request failed due to network, CORS, etc.
                return throwError('Error while requesting data');
            })
        );

    }
//app.ts
    this.service.getStatus().subscribe(data => {

        //I expect this function to be called ONLY if there was no throwError(), but that wasn't the case
        //No matter what I try in `service.ts`, this will always be called

    }, (error) => {

       //I expect this to call when throwError() is called from `service.ts` but it never happens

    });

Я также прочитал другое предложение использовать catch() для subscribe(), но catch() никогда не был методом для подписки:

//app.ts
    this.service.getStatus().subscribe(data => {

        //I expect this function to be called ONLY if there was no throwError(), but that wasn't the case
        //No matter what I try in `service.ts`, this will always be called

    }).catch(error => {

        //This is not valid

    });

Ничто из того, что я пробовал, не сработало, и в трубе есть несколько мест, которые я могу throwError(), но я не совсем уверен, в чем их разница (например, catchError() в service.ts и error из subscribe(success, error) в app.ts.


person timthekoder    schedule 06.05.2020    source источник
comment
Это на самом деле вызовет ошибку, как я и ожидал! Не могли бы вы представить это как ответ, чтобы я мог как-то его принять?   -  person timthekoder    schedule 07.05.2020


Ответы (1)


Мне кажется немного сложным. Если вы не хотите реализовывать перехватчик http, я бы просто сделал что-то вроде этого

//service.ts
  getStatus() {
    return this.http.get('http://www.test.com');
  }

А потом

//app.ts
    this.testService.getStatus()
      .subscribe(data => {
        if ('error' in data) {
          // process Error       
          return;
        }
        // process data
        console.log(data);
      }, error => {
        // http error
        console.log(error);
      });

Для оператора tap он используется для выполнения любых действий, которые вы хотите использовать с данными или нет (например, ведение журнала), но он всегда будет возвращать наблюдаемое, идентичное его источнику.

person François Minh    schedule 06.05.2020
comment
Ух ты. Это проще, чем я думал. Я, возможно, переосмыслил это. Будет ли tap() активирован, даже если http() вернет ошибку? - person timthekoder; 07.05.2020
comment
Нет, нажатие произойдет, если будут возвращены некоторые данные. - person François Minh; 07.05.2020