Пример Angular Interceptors

Главной особенностью @angular/common/http является interceptors, возможность объявлять перехватчики, которые находятся между вашим приложением и бэкэндом. Когда ваше приложение делает запрос, перехватчики преобразуют его перед отправкой на сервер (Удобно добавлять заголовки к запросом). Применяется для всего: от аутентификации до логирования.

Создание приложения

ng new interceptors
cd interceptors
ng g service api

Создадим сервис api.service.ts, который будет получать данные с jsonplaceholder.typicode.com

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

export interface Posts {
  userId: number;
  id: number;
  title: string;
  body: string;
}

@Injectable()
export class ApiService {

  private postsURL = 'https://jsonplaceholder.typicode.com/posts';

  constructor(private http: HttpClient) { }

  getData(): Observable<Posts> {

    return this.http
      .get<Posts>(this.postsURL);
  }

}

В главный модуль app.module.ts добавляем

import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; // <- добавлено

...
  imports: [
    BrowserModule,
    HttpClientModule // <- добавлено
  ],
...

HTML код app компонента

<div style="text-align:center">
  <h1>
    Welcome to {{title}}!
  </h1>
  <img width="300" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<div class="container">
  <div class="row">
      <table class="table">
          <thead class="thead-inverse">
            <tr>
                <th class="text-center">ID</th>
                <th class="text-center">Title</th>
                <th class="text-center">Body</th>
            </tr>
          </thead>
          <tbody>
            <tr *ngFor="let post of posts">
                <td>{{post.id}}</td>
                <td class="text-center">{{post.title}}</td>
                <td>{{post.body}}</td>
            </tr>
          </tbody>
      </table>
  </div>
</div>

Написание перехватчика

Чтобы реализовать перехватчик, нужно создать класс, реализующий интерфейс HttpInterceptor, который имеет один метод intercept(). Он принимает два параметра (req, next) и возварщает Observable. По сути первый параметр входящий запрос, второй - исходящий. Поэтому нам необходимо вернуть запрос, делается через метод handle. Далее следует зарегистрировать класс перехватчика в приложении.

ng g class api.interceptor

Для начала создадим простой перехватчик, который ничего не делает, просто принимает и отправляет запрос, не изменяя его:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';

@Injectable()
export class ParamInterceptor implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(req);
    }
}

Теперь нужно зарегистрировать перехватчик. Сделаем это в app.module.ts.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; // <- добавлено

import { AppComponent } from './app.component';
import { ApiService } from './api.service';
import { AuthInterceptor, ParamInterceptor } from './api.interceptor';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule // <- добавлено
  ],
  providers: [
    ApiService, {
    provide: HTTP_INTERCEPTORS,
    useClass: ParamInterceptor,
    multi: true
  }],
  bootstrap: [AppComponent]
})
export class AppModule { }

Теперь все запросы в приложении обрабатываются перехватчиком ParamInterceptor. Добавим логики. Будем добавлять параметр UserId = 7, для запросов к серверу jsonplaceholder.typicode.com.

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';

@Injectable()
export class ParamInterceptor implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    if (req.url.includes('jsonplaceholder.typicode.com')) {
        const paramReq = req.clone({
            params: req.params.set(
                'userId',
                '7'
            )
        });
        return next.handle(paramReq);
    } else {
        return next.handle(req);
    }

    }
}

Функция clone используется, потому что объект req является immutable (Неизменяемым).

Результат

Посмотреть на GitHub, Stackblitz

Похожие записи

Angular routerLink conditionally

<a [routerLink]="myVar ? '/home' : null" routerLinkActive="is-active">Home</a>
or
<a [routerLink]="myVar ? ['/home'] : []">Home</a>
02 сентября 2019 г. в Angular

Angular environment service

Использование сервиса для окружения вместо прямой ссылки на environment.ts

26 января 2020 г. в Angular

Вложенные формы Angular

Рассматриваются варианты встраивания форм, позволяющие переиспользовать набор полей вводе со своей логикой. @Input() родительской формы, @Output() дочерней формы, ViewChild(), ControlValueAccessor, ControlContainer