Angular 6 & 7 HTTP Client Interceptor с обработкой ошибок

Код
В данном руководстве объясняется, как в Angular 6 и 7 с помощью интерцепторов (перехватчиков) обрабатывать HTTP-запросы и ответы.
Ресурсы
Нам понадобиться node.js 8.12.0 и npm v6.4.1, а также Angular CLI.
$ npm install -g angular-cli
Вам также необходимо иметь общее представление о создании приложений с помощью Angular CLI.
Создание приложения
Для создания приложения в CLI выполните следующие команды:
$ ng new Angular-Interceptor
$ cd Angular-Interceptor
$ ng serve
После этого открываем в браузере ссылку http://localhost:4200 и добавляем компонент material в Angular-приложение. Он нужен для улучшения работы пользовательского интерфейса. Подробное описание установки компонента можно найти здесь.
Шаг 1: Установка Angular Material, Angular CDK и Angular Animations
Выполните следующие команды:
npm install --save @angular/material @angular/cdk @angular/animations
Шаг 2: Настройка анимации
Импортируйте BrowserAnimationsModule в свой AppModule
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@NgModule({
...
imports: [BrowserAnimationsModule],
...
})
export class AppModule { }
Шаг 3: Импортирование модулей компонентов
Импортируем MatDialogModule в модуль AppModule.
import { MatDialogModule } from '@angular/material';
@NgModule({
imports: [MatDialogModule],
})
export class AppModule { }
Шаг 4: Добавление темы
Добавьте эту строку в файл styles.css
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
Создание перехватчика Angular
Создайте папку для перехватчика с именем вашего приложения. После этого создайте новый файл httpconfig.interceptor.ts в папке интерцептора.
Подключите следующие зависимости в файле httpconfig.interceptor.ts
import { Injectable } from '@angular/core';
import { ErrorDialogService } from '../error-dialog/errordialog.service';
import {
HttpInterceptor,
HttpRequest,
HttpResponse,
HttpHandler,
HttpEvent,
HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
В Angular 6 и 7 rxjs map изменяется на путь rxjs/operators. Будьте внимательны во время процесса импортирования.
Создаем класс HttpConfigInterceptor ** и реализуем интерфейс HttpInterceptor**
export class HttpConfigInterceptor implements HttpInterceptor
@Injectable() export class HttpConfigInterceptor implements HttpInterceptor { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {}
В данном примере мы устанавливаем токен Content-Type и Accept type в запросе API.
const token: string = localStorage.getItem('token');
request = request.clone({ headers: request.headers.set('Authorization', 'Bearer ' + token) });
request = request.clone({ headers: request.headers.set('Content-Type', 'application/json') });
request = request.clone({ headers: request.headers.set('Accept', 'application/json') });
Ниже приведен весь код:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token: string = localStorage.getItem('token');
if (token) {
request = request.clone({ headers: request.headers.set('Authorization', 'Bearer ' + token) });
}
if (!request.headers.has('Content-Type')) {
request = request.clone({ headers: request.headers.set('Content-Type', 'application/json') });
}
request = request.clone({ headers: request.headers.set('Accept', 'application/json') });
return next.handle(request).pipe(
map((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
console.log('event--->>>', event);
}
return event;
}));
}
Из кода, приведенного выше, мы можем установить Content-Type, Accept type и токен в API. Он обрабатывает только API-запрос.
map((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
console.log('event--->>>', event);
// this.errorDialogService.openDialog(event);
}
return event;
}),
Приведенный выше код будет обрабатывать ответ API. Мы можем обрабатывать каждый отклик API.
Для обработки ответа об ошибке нужно импортировать модуль rxjs
import { map, catchError } from 'rxjs/operators';
Код, приведенный ниже, будет обрабатывать ответ об ошибке:
catchError((error: HttpErrorResponse) => {
let data = {};
data = {
reason: error && error.error.reason ? error.error.reason : '',
status: error.status
};
this.errorDialogService.openDialog(data);
return throwError(error);
})
Здесь я добавил errorDialogService для обработки ошибок и отображения сообщения об ошибке, предназначенного для пользователей. Но сначала нужно импортировать httpconfig.interceptor.ts ** в модуль AppModule**.
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpConfigInterceptor} from './interceptor/httpconfig.interceptor';
Добавляем свой класс в провайдеры. Для обработки множественных перехватов устанавливаем multi: true
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true }
]
Создание отдельной службы для обработки ошибок
Чтобы обрабатывать ответы об ошибке, создаем новый файл errordialof.sercive.ts с использованием приведенного ниже кода:
import { Injectable } from '@angular/core';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { ErrorDialogComponent } from './errordialog.component';
@Injectable()
export class ErrorDialogService {
constructor(public dialog: MatDialog) { }
openDialog(data): void {
const dialogRef = this.dialog.open(ErrorDialogComponent, {
width: '300px',
data: data
});
dialogRef.afterClosed().subscribe(result => {
console.log('The dialog was closed');
let animal;
animal = result;
});
}
}
Добавляем компонент errordialog.component для отображения диалогового окна о возникновении ошибки.
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material';
@Component({
selector: 'app-root',
templateUrl: './errordialog.component.html'
})
anexport class ErrorDialogComponent {
title = 'Angular-Interceptor';
constructor(@Inject(MAT_DIALOG_DATA) public data: string) {}
}
<div>
<div>
<p>
Reason: {{data.reason}}
</p>
<p>
Status: {{data.status}}
</p>
</div>
</div>
Импортируем файл errordialog.service и компонент диалога ошибок в модуль приложения.
Создание примера сервисного файла для HTTP-запроса
У меня есть пример файла службы для вызова API.
LogIn API Customer detail API
I have created the service name called login.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// import 'rxjs/operator/map';
@Injectable()
export class LoginService {
constructor(private http: HttpClient) { }
login(data) {
data = { email: 'admin', password: 'admin' };
return this.http.post('http://localhost:3070/api/login', data);
}
getCustomerDetails() {
return this.http.get('http://localhost:3070/customers/details');
}
}
Добавляем функцию для вызова двух API.
Запуск службы HTTP-клиента в компоненте приложения
Я использовал две функции function app.componet.ts: для логина API и вызова функции нажатия кнопки мышки.
import { Component } from '@angular/core';
import { LoginService } from './services/login.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'Angular-Interceptor';
constructor(public loginService: LoginService) {
this.loginService.login({}).subscribe(data => {
console.log(data);
});
}
getCustomerDetails() {
this.loginService.getCustomerDetails().subscribe((data) => {
console.log('----->>>', data);
});
}
}
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<h2>Here are some links to help you start: </h2>
<ul>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
</li>
<li>
<h2><p (click)="getCustomerDetails()">Get customer details</p></h2>
</li>
</ul>
<router-outlet></router-outlet>
Вот так выглядит диалоговое окно обработчика ошибок:

Пример кода
Я разместил полный код примера на github. Вы можете запустить npm и сервер ng для тестирования кода. Не забудьте изменить адрес API URL серверной части в файле входа в систему.
Заключение
Мы рассмотрели, как обрабатывать http-запрос и ответ на него с использованием перехватчиков в Angular 6 и 7 interceptor.