Как передать параметры URL (query string) в HTTP-запрос в Angular?
Использование HttpParams для чистых и безопасных запросов
В Angular есть встроенный механизм для работы с query-параметрами — класс HttpParams из пакета @angular/common/http. Он решает все ваши проблемы: автоматически экранирует спецсимволы, игнорирует пустые/null/undefined значения (если настроить), и делает код гораздо читаемее.
Вот как должен выглядеть ваш сервис:
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
interface User {
id: number;
name: string;
email: string;
}
@Injectable({ providedIn: 'root' })
export class UserService {
private apiUrl = '/api/users';
constructor(private http: HttpClient) {}
getUsers(page: number = 1, search: string = ''): Observable<User[]> {
// Создаём объект HttpParams и добавляем параметры
let params = new HttpParams()
.set('page', page.toString())
.set('limit', '10');
// Добавляем search только если он не пустой
if (search) {
params = params.set('search', search);
}
// Передаём params как второй аргумент
return this.http.get<User[]>(this.apiUrl, { params });
}
}
Почему это лучше ручной сборки строки?
- Автоматическое экранирование: если search содержит пробелы, амперсанды (&) или кириллицу, HttpParams сам закодирует их (например, "john doe" станет "john+doe", "тест" станет "%D1%82%D0%B5%D1%81%D1%82").
- Чистота URL: пустые параметры не добавляются, если вы используете проверку
if (search). - Гибкость: можно легко добавлять/удалять/изменять параметры.
- Типизация: TypeScript подскажет, какие методы доступны у HttpParams.
Расширенный пример с несколькими параметрами
Часто параметры приходят из формы или другого объекта. Вот как можно обработать динамический набор параметров:
interface UserFilters {
page?: number;
limit?: number;
search?: string;
sortBy?: string;
order?: 'asc' | 'desc';
}
getUsers(filters: UserFilters): Observable<User[]> {
let params = new HttpParams();
// Проходим по всем ключам объекта filters
Object.entries(filters).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== '') {
params = params.set(key, String(value));
}
});
return this.http.get<User[]>(this.apiUrl, { params });
}
// Использование:
this.userService.getUsers({
page: 1,
limit: 20,
search: 'john',
sortBy: 'name',
order: 'asc'
}).subscribe(users => console.log(users));
Важные методы HttpParams
set(param, value)— устанавливает значение параметра (если параметр уже существует, перезаписывает его).append(param, value)— добавляет ещё одно значение к существующему параметру (для массивов, например?tag=angular&tag=typescript).delete(param)— удаляет параметр.toString()— возвращает строку запроса (например,?page=1&limit=10&search=john).
Совет по иммутабельности
Обратите внимание: set() и append() не изменяют исходный объект, а возвращают новый. Поэтому мы используем let params = ... и переназначаем переменную. Это сделано для иммутабельности и предотвращения побочных эффектов.
Таким образом, используя HttpParams, вы получаете чистый, безопасный и легко поддерживаемый код. Это стандартный подход в Angular-приложениях.
Альтернатива: использование объекта с параметрами напрямую
Если вам не нужна сложная логика фильтрации (например, все параметры обязательны), можно передать объект params прямо в опции запроса, не создавая экземпляр HttpParams. Angular сам преобразует обычный объект в параметры запроса:
getUsers(page: number, limit: number): Observable<User[]> {
const params = {
page: page.toString(),
limit: limit.toString()
};
return this.http.get<User[]>(this.apiUrl, { params });
}
Этот способ короче, но имеет недостатки:
- Нет автоматического экранирования — если значения содержат спецсимволы, их нужно экранировать вручную через
encodeURIComponent(). - Нет методов
appendиdelete— для массивов параметров придётся писать свою логику. - Пустые значения всё равно попадут в URL, если их явно не отфильтровать.
Поэтому данный подход подходит только для простых случаев, когда параметры — это числа или короткие строки без спецсимволов. Для продакшн-кода рекомендую использовать HttpParams из первого ответа.