У меня есть служба данных, которая выглядит так:

@ Injectable ()
export class DataService {
    baseUrl = 'http://localhost'
        конструктор(
        частный httpClient: HttpClient) {
    }
    get (url, params): Promise  {

        вернуть this.sendRequest (this.baseUrl + url, 'get', null, params)
            .map ((res) => {
                вернуть res как объект
            })
            .обещать();
    }
    post (url, body): Promise  {
        вернуть this.sendRequest (this.baseUrl + url, 'post', body)
            .map ((res) => {
                вернуть res как объект
            })
            .обещать();
    }
    патч (url, body): Promise  {
        вернуть this.sendRequest (this.baseUrl + url, 'patch', body)
            .map ((res) => {
                вернуть res как объект
            })
            .обещать();
    }
    sendRequest (url, type, body, params = null): Observable  {
        вернуть this.httpClient [тип] (url, {params: params}, body)
    }
}

Если я получаю ошибку HTTP (например, 404), я получаю неприятное консольное сообщение: ERROR Ошибка: Неперехвачено (в обещании): [объект Object] из core.es5.js Как поступить в моем случае?

LastTribunal

Ответы (12)

У вас есть несколько вариантов, в зависимости от ваших потребностей. Если вы хотите обрабатывать ошибки для каждого запроса, добавьте в свой запрос catch. Если вы хотите добавить глобальное решение, используйте HttpInterceptor.

Откройте здесь рабочий демонстрационный плункер для решений ниже.

tl; dr

В простейшем случае вам просто нужно добавить .catch () или .subscribe (), например:

import 'rxjs / add / operator / catch'; // не забывайте об этом, иначе вы получите ошибку во время выполнения
this.httpClient
      .get ("URL-адрес данных")
      .catch ((ошибка: HttpErrorResponse) => {
        // простое ведение журнала, но вы можете сделать гораздо больше, см. ниже
        console.error ('Произошла ошибка:', err.error);
      });

// или
this.httpClient
      .get ("URL-адрес данных")
      .подписываться(
        data => console.log ('успех', данные),
        error => console.log ('ой', ошибка)
      );

Но об этом подробнее, см. Ниже.


Метод (локальный) решение: ошибка журнала и возврат резервного ответа

Если вам нужно обрабатывать ошибки только в одном месте, вы можете использовать catch и вернуть значение по умолчанию (или пустой ответ) вместо полного отказа. Вам также не нужен .map только для приведения, вы можете использовать универсальную функцию. Источник: Angular.io - Получение сведений об ошибке.

Итак, общий метод .get () будет выглядеть примерно так:

импорт {Injectable} из '@ angular / core';
импортировать {HttpClient, HttpErrorResponse} из "@ angular / common / http";
импортировать {Observable} из 'rxjs / Observable';
import 'rxjs / add / operator / catch';
import 'rxjs / add / observable / of';
import 'rxjs / add / observable / empty';
import 'rxjs / add / operator / retry'; // не забываем импорт

@Injectable ()
export class DataService {
    baseUrl = 'http://localhost';
    конструктор (частный httpClient: HttpClient) {}

    // обратите внимание на , делая метод универсальным
    get  (url, params): Observable  {
      вернуть this.httpClient
          .get  (this.baseUrl + url, {params})
          .retry (3) // необязательно добавить повтор
          .catch ((ошибка: HttpErrorResponse) => {

            if (err.error instanceof Error) {
              // Произошла ошибка на стороне клиента или сети. Обращайтесь с этим соответствующим образом.
              console.error ('Произошла ошибка:', err.error.message);
            } еще {
              // Серверная часть вернула неудачный код ответа.
              // Тело ответа может содержать информацию о том, что пошло не так,
              console.error (`Backend вернул код $ {err.status}, тело было: $ {err.error}`);
            }

            // ... при желании вернуть резервное значение по умолчанию, чтобы приложение могло продолжить работу (выберите одно)
            // которое может быть значением по умолчанию
            // возвращаем Observable.of  ({my: "значение по умолчанию ..."});
            // или просто пустой наблюдаемый
            return Observable.empty  ();
          });
     }
}

Обработка ошибки позволит приложению продолжить работу, даже если служба по URL-адресу находится в плохом состоянии.

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

Запустите рабочий демонстрационный плункер здесь.


Расширенное использование: перехват всех запросов или ответов

Еще раз, Гид по Angular.io показывает:

Основная особенность @ angular / common / http - это перехват, способность объявлять перехватчики, которые находятся между вашим приложением и серверной частью. Когда ваше приложение делает запрос, перехватчики преобразуют его перед отправкой на сервер, а перехватчики могут преобразовать ответ на обратном пути до того, как ваше приложение его увидит. Это полезно для всего, от аутентификации до регистрации.

Который, конечно, может быть использован для обработки ошибок очень простым способом (здесь демо-плункер):

импорт {Injectable} из '@ angular / core';
импортировать {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse,
         HttpErrorResponse} от '@ angular / common / http';
импортировать {Observable} из 'rxjs / Observable';
import 'rxjs / add / operator / catch';
import 'rxjs / add / observable / of';
import 'rxjs / add / observable / empty';
import 'rxjs / add / operator / retry'; // не забываем импорт

@Injectable ()
класс экспорта HttpErrorInterceptor реализует HttpInterceptor {
  перехват (запрос: HttpRequest , следующий: HttpHandler): Observable > {
    return next.handle (запрос)
      .catch ((ошибка: HttpErrorResponse) => {

        if (err.error instanceof Error) {
          // Произошла ошибка на стороне клиента или сети. Обращайтесь с этим соответствующим образом.
          console.error ('Произошла ошибка:', err.error.message);
        } еще {
          // Серверная часть вернула неудачный код ответа.
          // Тело ответа может содержать информацию о том, что пошло не так,
          console.error (`Backend вернул код $ {err.status}, тело было: $ {err.error}`);
        }

        // ... при желании вернуть резервное значение по умолчанию, чтобы приложение могло продолжить работу (выберите одно)
        // которое может быть значением по умолчанию (здесь должно быть HttpResponse)
        // возврат Observable.of (новый HttpResponse ({body: [{name: "Значение по умолчанию ..."}]}));
        // или просто пустой наблюдаемый
        return Observable.empty > ();
      });
  }
}

Предоставление вашего перехватчика: Простое объявление HttpErrorInterceptor выше не заставляет ваше приложение его использовать. Вам необходимо подключить его к вашему модулю приложения, указав его как перехватчик, как показано ниже:

импорт {NgModule} из '@ angular / core';
импортировать {HTTP_INTERCEPTORS} из '@ angular / common / http';
import {HttpErrorInterceptor} из './path/http-error.interceptor';

@NgModule ({
  ...
  провайдеры: [{
    предоставить: HTTP_INTERCEPTORS,
    useClass: HttpErrorInterceptor,
    мульти: правда,
  }],
  ...
})
класс экспорта AppModule {}

Примечание: Если у вас есть и перехватчик ошибок и некоторая локальная обработка ошибок, естественно, вероятно, что локальная обработка ошибок никогда не будет запущена, поскольку ошибка всегда будет обрабатываться перехватчиком до он достигает локальной обработки ошибок.

Запустите рабочий демонстрационный плункер здесь.

Позвольте мне обновить ответ acdcjuniorоб использовании HttpInterceptor с последними функциями RxJs (v.6).

импорт {Injectable} из '@ angular / core';
Импортировать {
  HttpInterceptor,
  HttpRequest,
  HttpErrorResponse,
  HttpHandler,
  HttpEvent,
  HttpResponse
} от '@ angular / common / http';

import {Observable, EMPTY, throwError, of} из 'rxjs';
импортировать {catchError} из 'rxjs / operator';

@Injectable ()
класс экспорта HttpErrorInterceptor реализует HttpInterceptor {
  перехват (запрос: HttpRequest , следующий: HttpHandler): Observable > {

    return next.handle (запрос) .pipe (
      catchError ((error: HttpErrorResponse) => {
        if (error.error instanceof Error) {
          // Произошла ошибка на стороне клиента или сети. Обращайтесь с этим соответствующим образом.
          console.error ('Произошла ошибка:', error.error.message);
        } еще {
          // Серверная часть вернула неудачный код ответа.
          // Тело ответа может содержать информацию о том, что пошло не так,
          console.error (`Backend вернул код $ {error.status}, тело было: $ {error.error}`);
        }

        // Если вы хотите вернуть новый ответ:
        // возврат (новый HttpResponse ({body: [{name: "Значение по умолчанию ..."}]}));

        // Если вы хотите вернуть ошибку на верхнем уровне:
        // возвращаем throwError (error);

        // или просто ничего не вернуть:
        return EMPTY;
      })
    );
  }
}

Используя Interceptor, вы можете поймать ошибку. Ниже код:

@ Injectable ()
класс экспорта ResponseInterceptor реализует HttpInterceptor {
  перехват (req: HttpRequest , next: HttpHandler): Observable > {
    // Получаем токен аутентификации от службы, который мы хотим передать через вызов службы
    const authToken: any = `Носитель $ {sessionStorage.getItem ('jwtToken')}`
    // Клонировать сервисный запрос и изменить исходные заголовки токеном аутентификации.
    const authReq = req.clone ({
      заголовки: req.headers.set ('Content-Type', 'application / json'). set ('Авторизация', authToken)
    });

    const authReq = req.clone ({setHeaders: {'Авторизация': authToken, 'Content-Type': 'application / json'}});

    // Отправляем клонированный запрос с заголовком следующему обработчику.
    return next.handle (authReq) .do ((event: HttpEvent ) => {
      if (событие instanceof HttpResponse) {
        console.log ("Сервисный ответ через перехватчик");
      }
    }, (err: any) => {
      if (err instanceof HttpErrorResponse) {
        console.log ("состояние ошибки", ошибка);
        if (err.status === 401 || err.status === 403) {
          location.href = '/ логин';
          console.log («Несанкционированный запрос - Срок действия токена аутентификации истек»);
        }
      }
    });
  }
}

Вы можете предпочесть этот блог.. на простом примере.

С появлением HTTPClient API был не только заменен Http API, но был добавлен новый, HttpInterceptor API.

AFAIK, одна из его целей - добавить поведение по умолчанию ко всем исходящим запросам и входящим ответам HTTP.

Итак, если предположить, что вы хотите добавить поведение обработки ошибок по умолчанию, добавление .catch () ко всем вашим возможным методам http.get / post / etc смехотворно сложно поддерживать.

Это можно сделать следующим образом, например, используя HttpInterceptor:

импорт {Injectable} из '@ angular / core';
импортировать {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse, HTTP_INTERCEPTORS} из '@ angular / common / http';
импортировать {Observable} из 'rxjs / Observable';
импортировать {_throw} из 'rxjs / observable / throw';
import 'rxjs / add / operator / catch';

/ **
 * Перехватывает HTTP-ответы и обрабатывает их в случае возникновения ошибки / исключения.
 * и извлеките из него соответствующую информацию.
 * /
@Injectable ()
класс экспорта ErrorInterceptor реализует HttpInterceptor {
    / **
     * Перехватывает исходящий HTTP-запрос, выполняет его и обрабатывает любые ошибки, которые могут возникнуть при выполнении.
     * @ см. HttpInterceptor
     * @param req исходящий HTTP-запрос
     * @param следующий обработчик HTTP-запроса
     * /
    перехват (req: HttpRequest , next: HttpHandler): Observable > {
        return next.handle (обязательно)
            .catch (errorResponse => {
                пусть errMsg: строка;
                if (errorResponse instanceof HttpErrorResponse) {
                    const err = errorResponse.message || JSON.stringify (errorResponse.error);
                    errMsg = `$ {errorResponse.status} - $ {errorResponse.statusText || ''} Подробности: $ {err} `;
                } еще {
                    errMsg = errorResponse.message? errorResponse.message: errorResponse.toString ();
                }
                return _throw (errMsg);
            });
    }
}

/ **
 * Провайдер POJO для перехватчика
 * /
export const ErrorInterceptorProvider = {
    предоставить: HTTP_INTERCEPTORS,
    useClass: ErrorInterceptor,
    мульти: правда,
};

// app.module.ts

импортировать {ErrorInterceptorProvider} из 'где-нибудь / в / вашу / src / папку';

@NgModule ({
   ...
   поставщики: [
    ...
    ErrorInterceptorProvider,
    ....
   ],
   ...
})
класс экспорта AppModule {}

Дополнительная информация для OP: вызов http.get / post / etc без строгого типа не является оптимальным использованием API. Ваш сервис должен выглядеть так:

// Эти интерфейсы могут быть где-то еще в вашей папке src, не обязательно в вашем служебном файле
интерфейс экспорта FooPost {
 // Определяем форму объекта в формате JSON, который ваш
 // ожидаем от бэкэнда при публикации
}

интерфейс экспорта FooPatch {
 // Определяем форму объекта в формате JSON, который ваш
 // ожидаем от бэкэнда на патч
}

интерфейс экспорта FooGet {
 // Определяем форму объекта в формате JSON, который ваш
 // ожидаем от бэкэнда при получении
}

@Injectable ()
export class DataService {
    baseUrl = 'http://localhost'
    конструктор(
        частный http: HttpClient) {
    }

    get (url, params): Observable  {

        вернуть this.http.get  (this.baseUrl + url, params);
    }

    post (url, body): Observable  {
        вернуть this.http.post  (this.baseUrl + url, body);
    }

    патч (url, body): Observable  {
        вернуть this.http.patch  (this.baseUrl + url, body);
    }
}

Возврат Promises из ваших методов обслуживания вместо Observables - еще одно плохое решение.

И еще один совет: если вы используете сценарий TYPE, начните использовать его часть типа. Вы теряете одно из самых больших преимуществ языка: знание типа значения, с которым вы имеете дело.

Если вам нужен, на мой взгляд, хороший пример angular-сервиса, взгляните на следующую суть.

Angular 8 Служба обработки ошибок HttpClient Пример

enter image description here

api.service.ts

    import { Injectable } from '@angular/core';
    import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
    import { Student } from '../model/student';
    import { Observable, throwError } from 'rxjs';
    import { retry, catchError } from 'rxjs/operators';

    @Injectable({
      providedIn: 'root'
    })
    export class ApiService {

      // API path
      base_path = 'http://localhost:3000/students';

      constructor(private http: HttpClient) { }

      // Http Options
      httpOptions = {
        headers: new HttpHeaders({
          'Content-Type': 'application/json'
        })
      }

      // Handle API errors
      handleError(error: HttpErrorResponse) {
        if (error.error instanceof ErrorEvent) {
          // A client-side or network error occurred. Handle it accordingly.
          console.error('An error occurred:', error.error.message);
        } else {
          // The backend returned an unsuccessful response code.
          // The response body may contain clues as to what went wrong,
          console.error(
            `Backend returned code ${error.status}, ` +
            `body was: ${error.error}`);
        }
        // return an observable with a user-facing error message
        return throwError(
          'Something bad happened; please try again later.');
      };


      // Create a new item
      createItem(item): Observable {
        return this.http
          .post(this.base_path, JSON.stringify(item), this.httpOptions)
          .pipe(
            retry(2),
            catchError(this.handleError)
          )
      }

     ........
     ........

    }

import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

const PASSENGER_API = 'api/passengers';

getPassengers(): Observable {
  return this.http
    .get(PASSENGER_API)
    .pipe(catchError((error: HttpErrorResponse) => throwError(error)));
}

Хуже всего то, что у вас нет приличной трассировки стека, которую вы просто не можете сгенерировать с помощью HttpInterceptor (надеюсь, что исправят). Все, что вы получаете, - это загрузка зоны и бесполезного раздувания rxjs, а не строка или класс, вызвавшие ошибку.

Для этого вам нужно будет сгенерировать стек в расширенном HttpClient, поэтому не рекомендуется делать это в производственной среде.

/**
 * Extended HttpClient that generates a stack trace on error when not in a production build.
 */
@Injectable()
export class TraceHttpClient extends HttpClient {
  constructor(handler: HttpHandler) {
    super(handler);
  }

  request(...args: [any]): Observable {
    const stack = environment.production ? null : Error().stack;
    return super.request(...args).pipe(
      catchError((err) => {
        // tslint:disable-next-line:no-console
        if (stack) console.error('HTTP Client error stack\n', stack);
        return throwError(err);
      })
    );
  }
}

Вероятно, вы захотите получить что-то вроде этого:

this.sendRequest(...)
.map(...)
.catch((err) => {
//handle your error here
})

Это также сильно зависит от того, как вы пользуетесь своим сервисом, но это основной случай.

Довольно просто (по сравнению с тем, как это было сделано в предыдущем API).

Источник (скопирован и вставлен) Официальное руководство по Angular

 http
  .get('/api/items')
  .subscribe(
    // Successful responses call the first callback.
    data => {...},
    // Errors will call this callback instead:
    err => {
      console.log('Something went wrong!');
    }
  );

Следуя ответу @acdcjunior, я реализовал его вот так

услуга:

  get(url, params): Promise {

            return this.sendRequest(this.baseUrl + url, 'get', null, params)
                .map((res) => {
                    return res as Object
                }).catch((e) => {
                    return Observable.of(e);
                })
                .toPromise();
        }

звонящий:

this.dataService.get(baseUrl, params)
            .then((object) => {
                if(object['name'] === 'HttpErrorResponse') {
                            this.error = true;
                           //or any handle
                } else {
                    this.myObj = object as MyClass 
                }
           });

Если вы не можете обнаружить ошибки ни с одним из предложенных здесь решений, возможно, сервер не обрабатывает запросы CORS.

В этом случае Javascript, а тем более Angular, может получить доступ к информации об ошибке.

Ищите предупреждения в вашей консоли, которые включают CORB или Cross-Origin Read Blocking.

Кроме того, изменился синтаксис обработки ошибок (как описано во всех остальных ответах). Теперь вы используете конвейерные операторы, например:

this.service.requestsMyInfo(payload).pipe(
    catcheError(err => {
        // handle the error here.
    })
);

Для Angular 6+ .catch не работает напрямую с Observable. Вы должны использовать

.pipe (catchError (this.errorHandler))

Ниже кода:

импорт {IEmployee} из './interfaces/employee';
импортировать {Injectable} из '@ angular / core';
импортировать {HttpClient, HttpErrorResponse} из '@ angular / common / http';
import {Observable, throwError} из 'rxjs';
импортировать {catchError} из 'rxjs / operator';

@Injectable ({
  providedIn: 'root'
})
экспорт класса EmployeeService {

  частный url = '/assets/data/employee.json';

  конструктор (частный http: HttpClient) {}

  getEmployees (): Observable  {
    вернуть this.http.get  (this.url)
                    .pipe (catchError (this.errorHandler)); // поймать ошибку
  }

  / ** Метод обработки ошибок * /

  errorHandler (error: HttpErrorResponse) {
    if (error.error instanceof ErrorEvent) {
      // Произошла ошибка на стороне клиента или сети. Обращайтесь с этим соответствующим образом.
      console.error ('Произошла ошибка:', error.error.message);
    } еще {
      // Серверная часть вернула неудачный код ответа.
      // Тело ответа может содержать информацию о том, что пошло не так,
      console.error (
        `Backend вернул код $ {error.status},` +
        `тело было: $ {error.error}`);
    }
    // возвращаем наблюдаемый объект с сообщением об ошибке пользователя
    вернуть throwError (
      «Произошло что-то плохое; Пожалуйста, повторите попытку позже.');
  }
}

Для получения дополнительных сведений см. Angular Guide для Http

2022 WebDevInsider