1. Знакомство с HttpClientModule
В Angular есть встроенный инструмент для работы с HTTP-запросами — HttpClientModule. Это как универсальный почтальон, который умеет отправлять ваши письма (запросы) на сервер и приносить обратно ответы (данные). Без него ваше приложение будет похоже на интроверта: красивое, но не особо общительное.
Почему нельзя просто использовать fetch или XMLHttpRequest?
Конечно, можно, но тогда вы потеряете массу удобств Angular:
- Автоматическая сериализация/десериализация JSON.
- Интеграция с RxJS (все запросы возвращают Observable).
- Глобальная обработка ошибок, перехватчики (interceptors), отмена запросов, и прочие плюшки.
- Простота тестирования и мокирования HTTP-запросов.
Вывод: Если вы пишете на Angular — используйте HttpClientModule. Это стандарт, и его синтаксис максимально дружелюбен для новичков.
Подключаем HttpClientModule
Чтобы пользоваться HTTP-запросами, нужно добавить HttpClientModule в массив imports главного модуля приложения (обычно это AppModule).
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http'; // Импортируем модуль
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
// ... ваши компоненты
],
imports: [
BrowserModule,
HttpClientModule, // Добавляем сюда!
// ... другие модули
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Важный момент:
Добавлять HttpClientModule нужно только один раз — обычно в главный модуль. Не надо импортировать его в каждый компонент (это не библиотека для шопоголиков!).
2. Базовый синтаксис работы с HttpClient
Теперь, когда модуль подключён, можно использовать сервис HttpClient для отправки запросов. Этот сервис внедряется (инжектируется) в ваш компонент или сервис через конструктор.
Пример: Получение данных с сервера (GET-запрос)
Допустим, у нас есть сервер, который по адресу https://jsonplaceholder.typicode.com/todos возвращает список задач. Давайте попробуем их получить.
1. Импортируем HttpClient:
import { HttpClient } from '@angular/common/http';
2. Инжектируем HttpClient в компонент:
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-todo-list',
template: `
<h2>Список задач</h2>
<ul>
<li *ngFor="let todo of todos">
{{ todo.title }}
</li>
</ul>
`
})
export class TodoListComponent implements OnInit {
todos: any[] = [];
constructor(private http: HttpClient) {}
ngOnInit() {
this.http.get<any[]>('https://jsonplaceholder.typicode.com/todos')
.subscribe(data => {
this.todos = data;
});
}
}
Пояснения:
- Мы внедряем HttpClient через конструктор компонента (Angular сам создаёт экземпляр).
- Вызываем метод get, указывая URL и (опционально) тип ожидаемых данных (any[] — массив любых объектов).
- Метод get возвращает Observable — мы подписываемся на него через .subscribe().
- Как только данные приходят, они попадают в переменную todos, и Angular автоматически обновляет шаблон.
Аналогия:
Представьте, что вы заказали пиццу. HttpClient.get — это звонок в пиццерию, а subscribe — это ожидание звонка курьера, который скажет: "Пицца у двери!". Пока пицца едет — вы можете заниматься своими делами.
3. Основные методы HttpClient
Сервис HttpClient поддерживает все основные HTTP-методы:
| Метод | Назначение | Пример вызова |
|---|---|---|
|
Получение данных | |
|
Отправка новых данных | |
|
Полное обновление данных | |
|
Частичное обновление данных | |
|
Удаление данных | |
Пример POST-запроса:
addTodo() {
const newTodo = { title: 'Купить хлеб', completed: false };
this.http.post('https://jsonplaceholder.typicode.com/todos', newTodo)
.subscribe(response => {
console.log('Создана задача:', response);
});
}
Важно:
В реальных приложениях лучше использовать отдельные сервисы для работы с HTTP, а не писать запросы прямо в компонентах. Но для простоты мы пока не будем усложнять архитектуру.
4. Как работает Observable в HttpClient
Все методы HttpClient возвращают Observable. Это значит, что запрос на сервер будет выполнен только после подписки (.subscribe(...)). До этого момента запрос «дремлет» и не занимает ресурсы.
Почему это хорошо?
- Можно легко отменять запросы (например, если пользователь ушёл со страницы).
- Можно комбинировать запросы, обрабатывать ошибки, делать retry и прочие чудеса RxJS.
- Observable — это как «подписка на новости»: пока не подписался — газета не приходит.
Пример: обработка ошибок
this.http.get('https://jsonplaceholder.typicode.com/todos')
.subscribe(
data => { this.todos = data; },
error => { console.error('Ошибка загрузки:', error); }
);
5. Типизация данных
Angular позволяет указывать, какого типа данные вы ожидаете получить. Это повышает безопасность и удобство работы с результатами.
interface Todo {
userId: number;
id: number;
title: string;
completed: boolean;
}
this.http.get<Todo[]>('https://jsonplaceholder.typicode.com/todos')
.subscribe(todos => {
// Теперь todos — это массив объектов типа Todo.
this.todos = todos;
});
Зачем это нужно?
Если вы попробуете обратиться к несуществующему свойству, TypeScript предупредит вас об ошибке ещё до запуска приложения. Это как иметь инструкцию к мебели: меньше шансов собрать шкаф вверх ногами.
6. Кратко о параметрах и заголовках
Часто нужно передавать параметры (например, фильтрацию, пагинацию) или заголовки (например, токен авторизации).
Пример с параметрами:
import { HttpParams } from '@angular/common/http';
const params = new HttpParams().set('userId', '1');
this.http.get<Todo[]>('https://jsonplaceholder.typicode.com/todos', { params })
.subscribe(todos => {
this.todos = todos;
});
Пример с заголовками:
import { HttpHeaders } from '@angular/common/http';
const headers = new HttpHeaders().set('Authorization', 'Bearer my-token');
this.http.get<Todo[]>('https://jsonplaceholder.typicode.com/todos', { headers })
.subscribe(todos => {
this.todos = todos;
});
7. Практика: добавляем HTTP-запросы в наше приложение
Давайте добавим в наше учебное приложение компонент, который будет получать и отображать список пользователей с сервера.
Шаг 1. Создаём компонент:
ng generate component user-list
Шаг 2. Реализуем компонент:
// user-list.component.ts
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
interface User {
id: number;
name: string;
email: string;
}
@Component({
selector: 'app-user-list',
template: `
<h2>Пользователи</h2>
<ul>
<li *ngFor="let user of users">
{{ user.name }} ({{ user.email }})
</li>
</ul>
`
})
export class UserListComponent implements OnInit {
users: User[] = [];
constructor(private http: HttpClient) {}
ngOnInit() {
this.http.get<User[]>('https://jsonplaceholder.typicode.com/users')
.subscribe(users => {
this.users = users;
});
}
}
Шаг 3. Добавляем компонент в шаблон app.component.html:
<app-user-list></app-user-list>
Шаг 4. Проверяем в браузере:
Если вы всё сделали правильно, увидите список пользователей, полученных с сервера.
8. Типичные ошибки при подключении и использовании HttpClientModule
Ошибка №1: забыли импортировать HttpClientModule
Самая частая проблема — забыли добавить HttpClientModule в массив imports в AppModule. В результате Angular будет ругаться примерно так:
NullInjectorError: No provider for HttpClient!
Решение: проверьте, что импорт есть, и он добавлен в imports.
Ошибка №2: импортировали HttpClientModule не в том модуле
Если вы используете lazy-loaded модули (ленивую загрузку), а запросы делаете из компонентов этих модулей, убедитесь, что HttpClientModule импортирован в основном модуле (обычно достаточно один раз — в AppModule). Повторный импорт обычно не нужен.
Ошибка №3: не подписались на Observable
Методы get, post и другие возвращают Observable. Если не вызвать .subscribe(), запрос не отправится! Иногда новички удивляются: «Почему сервер не отвечает?» — а на самом деле запрос даже не был отправлен.
Ошибка №4: неправильная работа с асинхронностью
Пытаться вернуть результат из метода до завершения запроса — частая ошибка. Например:
getUsers(): User[] {
let users: User[] = [];
this.http.get<User[]>('...').subscribe(data => users = data);
return users; // ← На этом этапе users всё ещё пустой!
}
Правильно — работать с Observable или подписываться там, где нужны данные.
Ошибка №5: забыли про типизацию
Если не указать тип данных (<User[]>), TypeScript не сможет предупредить вас об ошибках в структуре ответа. Это не критично, но рано или поздно приведёт к багам.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ