Как обрабатывать ошибки в Angular?

В Angular ошибки могут возникать в различных контекстах: при выполнении HTTP-запросов, в жизненном цикле компонентов, в шаблонах, при загрузке маршрутов и модулей, а также на уровне глобального приложения. Обработка ошибок — это важная часть архитектуры любого Angular-приложения, особенно для обеспечения стабильности, информативности и улучшения пользовательского опыта. Angular предоставляет несколько механизмов для локальной и глобальной обработки ошибок.

1. Обработка ошибок в HTTP-запросах

1.1. Оператор catchError (RxJS)

Для перехвата ошибок HTTP-запросов используется оператор catchError из RxJS:

import { catchError } from 'rxjs/operators';
import { throwError, of } from 'rxjs';
this.http.get('/api/data').pipe(
catchError(error => {
console.error('Ошибка:', error);
return throwError(() => error);
})
).subscribe({
next: data => console.log(data),
error: err => console.log('Обработано в subscribe')
});

1.2. Возврат альтернативного значения

.pipe(
catchError(error => {
return of(\[\]); // Возврат безопасного значения
})
)

1.3. Повтор запроса при ошибке

import { retry } from 'rxjs/operators';
this.http.get('/api/data')
.pipe(retry(3))
.subscribe();

2. Глобальный перехват HTTP-ошибок (интерсептор)

Создание HttpInterceptor для глобального логгирования и перенаправлений:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';
import { Observable, catchError, throwError } from 'rxjs';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
intercept(req: HttpRequest&lt;any&gt;, next: HttpHandler): Observable&lt;HttpEvent<any&gt;> {
return next.handle(req).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 401) {
// перенаправить на логин
}
console.error('HTTP Error:', error);
return throwError(() => error);
})
);
}
}

Регистрация:

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

3. Глобальная обработка ошибок — ErrorHandler

Angular предоставляет класс ErrorHandler для перехвата необработанных исключений:

import { ErrorHandler, Injectable } from '@angular/core';
@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
handleError(error: any): void {
console.error('Глобальная ошибка:', error);
// логирование на сервер
// уведомление пользователя
}
}

Регистрация:

providers: \[
{ provide: ErrorHandler, useClass: GlobalErrorHandler }
\]

Этот обработчик перехватывает ошибки, которые не были пойманы внутри try/catch или Observable.catchError.

4. Обработка ошибок в шаблоне

В шаблоне Angular не выбрасывает ошибки напрямую, но можно использовать ngIf, try/catch в pipe-функциях и безопасную навигацию:

&lt;div \*ngIf="user?.profile?.name"&gt;{{ user.profile.name }}&lt;/div&gt;

Также можно использовать кастомные пайпы с безопасной логикой:

@Pipe({ name: 'safeJson' })
export class SafeJsonPipe implements PipeTransform {
transform(value: string): any {
try {
return JSON.parse(value);
} catch {
return null;
}
}
}

5. Ошибки в ngOnInit и других хуках

Ошибки в lifecycle-хуках можно обрабатывать через try/catch:

ngOnInit() {
try {
this.loadData();
} catch (e) {
console.error('Ошибка в ngOnInit:', e);
}
}

Однако Angular всё равно прокинет ошибку выше, если она не была поймана. Лучше использовать RxJS и обработку через catchError или tap.

6. Обработка ошибок загрузки маршрутов (Lazy Loading)

При ошибках при ленивой загрузке модулей можно использовать RouterModule с ErrorHandler или ловить ошибки в навигации:

this.router.events.subscribe(event => {
if (event instanceof NavigationError) {
console.error('Ошибка загрузки маршрута:', event.error);
}
});

7. Обработка ошибок форм

Template-driven:

&lt;input name="email" \[(ngModel)\]="email" required email #emailRef="ngModel" /&gt;
&lt;div \*ngIf="emailRef.errors?.required"&gt;Email обязателен&lt;/div&gt;
&lt;div \*ngIf="emailRef.errors?.email"&gt;Некорректный email&lt;/div&gt;

Reactive forms:

this.form = this.fb.group({
email: \['', \[Validators.required, Validators.email\]\]
});
&lt;input formControlName="email" /&gt;
&lt;div \*ngIf="form.get('email')?.hasError('required')"&gt;Обязательное поле&lt;/div&gt;
&lt;div \*ngIf="form.get('email')?.hasError('email')"&gt;Некорректный email&lt;/div&gt;

8. Вывод ошибок в UI

Можно использовать глобальные сервисы для отображения ошибок пользователю:

@Injectable({ providedIn: 'root' })
export class NotificationService {
showError(message: string) {
// отображение через toast, snackbar или модалку
}
}

Интеграция с перехватчиком:

catchError(error => {
this.notifier.showError('Произошла ошибка');
return throwError(() => error);
})

9. Логгирование на сервер

Часто глобальный ErrorHandler используется для отправки ошибок на внешний сервер логов:

this.http.post('/log-error', {
message: error.message,
stack: error.stack
}).subscribe();

10. Использование try/catch с await

В асинхронных методах:

async loadData() {
try {
const data = await this.http.get('/api/data').toPromise();
} catch (e) {
console.error('Ошибка при загрузке данных:', e);
}
}

11. Перехват ошибок при инициализации приложения (APP_INITIALIZER)

Если приложение требует асинхронной инициализации, ошибки в APP_INITIALIZER могут быть фатальными:

{
provide: APP_INITIALIZER,
useFactory: (configService: ConfigService) => () => configService.load().catch(err => {
console.error('Ошибка инициализации', err);
return Promise.resolve(); // предотвращает сбой загрузки
}),
deps: \[ConfigService\],
multi: true
}

12. Angular Zones и ошибки

Angular использует NgZone для контроля изменений. Ошибки вне зоны (например, из сторонних библиотек) могут быть не задетектированы. Можно явно запускать логику в зоне:

this.zone.run(() => {
this.data = updatedValue;
});

13. Инструменты

  • Sentry, LogRocket, Rollbar — для автоматического сбора фронтенд-ошибок.

  • console.error, Debugger, window.onerror, Error.stack — для локальной отладки.

14. Поведение throwError

Начиная с RxJS 7:

return throwError(() => new Error('Ошибка'));

Передача функции, а не объекта, обязательна для правильной работы.

15. Навигация по ошибке

Если возникает ошибка — можно выполнить редирект:

catchError(error => {
this.router.navigate(\['/error-page'\]);
return throwError(() => error);
})

Angular предоставляет как локальные, так и централизованные инструменты для надёжной и гибкой обработки ошибок. Использование перехватчиков, глобального ErrorHandler, реактивного подхода с catchError, и UI-уведомлений — основа продуманной стратегии обработки ошибок.