JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /HTTP Interceptors: назначение, базовый пример

HTTP Interceptors: назначение, базовый пример

Модуль 4: Node.js, Next.js и Angular
17 уровень , 9 лекция
Открыта

1. Знакомство с HTTP Interceptor

Давайте начнём с аналогии. Представьте себе почтовое отделение. Каждый раз, когда вы отправляете письмо (HTTP-запрос), оно сначала попадает к секретарю (Interceptor), который может проверить его, добавить штамп или даже завернуть письмо обратно, если оно не соответствует правилам. Аналогично, когда приходит ответ, секретарь тоже может его перехватить, например, проверить подпись или вложить дополнительную инструкцию.

HTTP Interceptor — это специальный класс в Angular, который перехватывает все ваши HTTP-запросы и ответы, проходящие через HttpClient. Он позволяет:

  • Автоматически добавлять заголовки (например, токен авторизации) ко всем запросам.
  • Централизованно обрабатывать ошибки (например, если сервер вернул 401 Unauthorized).
  • Логировать все HTTP-запросы и ответы для отладки.
  • Модифицировать тело запроса/ответа, если это необходимо.
  • Реализовать повторные попытки (retry) при ошибках или показывать спиннер загрузки.

Всё это можно делать, не трогая код в каждом компоненте или сервисе! Interceptor — это как “единая точка входа” для всей сетевой активности вашего приложения.

Как работает Interceptor в Angular

В Angular Interceptor — это просто сервис, реализующий интерфейс HttpInterceptor. Вы реализуете метод intercept, который получает исходный запрос и следующий обработчик (next), а возвращает Observable с ответом.

Схематично:


Component/Service
      ↓
  Interceptor 1
      ↓
  Interceptor 2
      ↓
  ... (ещё interceptors)
      ↓
  HttpClient (отправляет запрос на сервер)
      ↓
  ... (ответ проходит обратно через interceptors)
      ↓
Component/Service

Все interceptors складываются в цепочку (chain), и каждый может модифицировать запрос или ответ.

2. Простейший пример Interceptor: логирование запросов

Давайте напишем свой первый Interceptor, который будет просто логировать все HTTP-запросы и ответы.

Шаг 1: Генерируем Interceptor через Angular CLI

ng generate interceptor logging

Это создаст файл logging.interceptor.ts с заготовкой класса.

Шаг 2: Реализуем интерфейс HttpInterceptor

Вот базовый код для логирующего Interceptor:

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

@Injectable()
export class LoggingInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log('[LoggingInterceptor] Отправка запроса:', req.url, req);

    // Передаём запрос дальше по цепочке
    return next.handle(req).pipe(
      tap({
        next: (event) => {
          console.log('[LoggingInterceptor] Получен ответ:', event);
        },
        error: (err) => {
          console.error('[LoggingInterceptor] Ошибка:', err);
        }
      })
    );
  }
}

Что тут происходит:

  • Перед отправкой запроса мы выводим его в консоль.
  • После получения ответа (или ошибки) — тоже логируем.
  • next.handle(req) передаёт запрос дальше (либо следующему interceptor, либо уже на сервер).

Шаг 3: Регистрируем Interceptor в приложении

Вам нужно добавить Interceptor в массив провайдеров, чтобы Angular его использовал:

// app.module.ts

import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { LoggingInterceptor } from './logging.interceptor';

@NgModule({
  // ...
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true }
  ]
})
export class AppModule { }

Ключевой момент: используем multi: true, чтобы Angular мог использовать несколько interceptors одновременно.

Теперь все запросы, проходящие через HttpClient, будут логироваться этим Interceptor.

3. Пример: Добавление заголовка авторизации

Частая задача — автоматически подставлять токен авторизации ко всем запросам, если пользователь залогинен. Для этого Interceptor — идеальный инструмент.

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

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // Обычно токен берут из сервиса авторизации
    const authToken = localStorage.getItem('auth_token');

    // Клонируем запрос и добавляем заголовок, если токен есть
    let authReq = req;
    if (authToken) {
      authReq = req.clone({
        setHeaders: {
          Authorization: `Bearer ${authToken}`
        }
      });
    }

    // Передаём дальше
    return next.handle(authReq);
  }
}

Обратите внимание:
В Angular объекты HttpRequest иммутабельны — их нельзя менять напрямую, только клонировать с нужными изменениями через .clone().

4. Пример: Централизованная обработка ошибок

Хотите, чтобы при ошибке 401 пользователя сразу выкидывало на страницу логина, а при 500 — показывалось дружелюбное сообщение? Interceptor снова поможет!

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

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
  constructor(private router: Router) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).pipe(
      catchError((error: HttpErrorResponse) => {
        if (error.status === 401) {
          // Неавторизован — редиректим на логин
          this.router.navigate(['/login']);
        } else if (error.status === 500) {
          alert('На сервере произошла ошибка. Попробуйте позже!');
        }
        // Пробрасываем ошибку дальше
        return throwError(() => error);
      })
    );
  }
}

5. Несколько Interceptors: порядок и best practices

Можно зарегистрировать сколько угодно interceptors. Они будут вызваны в том порядке, в каком вы их указали в массиве providers.
Например:

providers: [
  { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
  { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true },
  { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }
]

Порядок важен!

  • Сначала AuthInterceptor добавит токен.
  • Потом LoggingInterceptor залогирует уже модифицированный запрос.
  • Потом ErrorInterceptor обработает возможные ошибки.

Совет:

  • Не делайте тяжелых синхронных вычислений или долгих асинхронных операций в interceptor — это может замедлить все HTTP-запросы.
  • Не забывайте вызывать next.handle(req)! Если забыть — запрос никогда не уйдёт на сервер, и вы получите "тишину в эфире".

6. Типичные ошибки при работе с HTTP Interceptors

Ошибка №1: Не зарегистрировали interceptor или забыли multi: true.
В этом случае Angular возьмёт только последний interceptor, остальные проигнорирует. Всегда используйте multi: true.

Ошибка №2: Не вызвали next.handle(req).
Если забыли вызвать этот метод, запрос не пойдёт дальше по цепочке и не дойдёт до сервера. Это как забыть отправить письмо после того, как вы его написали.

Ошибка №3: Изменяете объект запроса напрямую.
Объекты HttpRequest иммутабельны! Используйте .clone() для любых изменений.

Ошибка №4: Слишком сложная логика или тяжёлые вычисления в interceptor.
Interceptor должен быть лёгким и быстрым — не делайте там долгих запросов к серверу или сложных вычислений.

Ошибка №5: Порядок регистрации interceptors не соответствует ожиданиям.
Запросы проходят через interceptors в том порядке, в каком они объявлены, а ответы — в обратном. Если порядок важен (например, логировать уже с добавленным токеном), расставьте interceptors правильно.

Ошибка №6: Не пробрасываете ошибку дальше (throwError).
Если вы “глотаете” ошибку в interceptor, компонент никогда не узнает, что запрос завершился неудачей.

1
Задача
Модуль 4: Node.js, Next.js и Angular, 17 уровень, 9 лекция
Недоступна
Получение и отображение списка пользователей через HTTP
Получение и отображение списка пользователей через HTTP
1
Задача
Модуль 4: Node.js, Next.js и Angular, 17 уровень, 9 лекция
Недоступна
Галерея изображений с асинхронной загрузкой и фильтрацией
Галерея изображений с асинхронной загрузкой и фильтрацией
1
Задача
Модуль 4: Node.js, Next.js и Angular, 17 уровень, 9 лекция
Недоступна
Форма добавления заметки с отправкой на сервер (POST) и оптимистичным обновлением
Форма добавления заметки с отправкой на сервер (POST) и оптимистичным обновлением
1
Задача
Модуль 4: Node.js, Next.js и Angular, 17 уровень, 9 лекция
Недоступна
Дашборд пользователей с фильтрацией и обработкой ошибок (RxJS operators)
Дашборд пользователей с фильтрацией и обработкой ошибок (RxJS operators)
1
Задача
Модуль 4: Node.js, Next.js и Angular, 17 уровень, 9 лекция
Недоступна
Каталог товаров с асинхронной подгрузкой, удалением и сортировкой (RxJS + HTTP)
Каталог товаров с асинхронной подгрузкой, удалением и сортировкой (RxJS + HTTP)
3
Опрос
async pipe, 17 уровень, 9 лекция
Недоступен
async pipe
async pipe
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ