HttpClient基础 #
一、HttpClient概述 #
HttpClient是Angular提供的HTTP客户端,用于与后端API进行通信。
text
┌─────────────────────────────────────────────────────┐
│ Angular 应用 │
├─────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────┐ │
│ │ HttpClient │ │
│ │ GET | POST | PUT | DELETE | PATCH │ │
│ └─────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────┐ │
│ │ HTTP拦截器 │ │
│ │ 认证 | 日志 | 错误处理 │ │
│ └─────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────┐ │
│ │ 后端 API │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
二、配置HttpClient #
2.1 导入HttpClient #
typescript
import { provideHttpClient } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient()
]
};
2.2 注入HttpClient #
typescript
import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) {}
}
三、GET请求 #
3.1 基本GET请求 #
typescript
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class UserService {
private apiUrl = 'https://api.example.com/users';
constructor(private http: HttpClient) {}
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl);
}
getUser(id: number): Observable<User> {
return this.http.get<User>(`${this.apiUrl}/${id}`);
}
}
3.2 带查询参数 #
typescript
import { HttpParams } from '@angular/common/http';
getUsers(params: { page?: number; size?: number; name?: string }): Observable<User[]> {
let httpParams = new HttpParams();
if (params.page) {
httpParams = httpParams.set('page', params.page.toString());
}
if (params.size) {
httpParams = httpParams.set('size', params.size.toString());
}
if (params.name) {
httpParams = httpParams.set('name', params.name);
}
return this.http.get<User[]>(this.apiUrl, { params: httpParams });
}
// 或使用fromObject
getUsers2(params: any): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl, {
params: {
page: params.page || 1,
size: params.size || 10,
name: params.name || ''
}
});
}
3.3 带请求头 #
typescript
import { HttpHeaders } from '@angular/common/http';
getUserWithHeaders(id: number): Observable<User> {
const headers = new HttpHeaders({
'Authorization': 'Bearer token123',
'Content-Type': 'application/json'
});
return this.http.get<User>(`${this.apiUrl}/${id}`, { headers });
}
3.4 完整请求选项 #
typescript
getUsersWithOptions(): Observable<HttpResponse<User[]>> {
return this.http.get<User[]>(this.apiUrl, {
params: { page: '1', size: '10' },
headers: new HttpHeaders({
'Authorization': 'Bearer token'
}),
observe: 'response',
responseType: 'json'
});
}
四、POST请求 #
4.1 基本POST请求 #
typescript
createUser(user: User): Observable<User> {
return this.http.post<User>(this.apiUrl, user);
}
4.2 带请求头 #
typescript
createUserWithHeaders(user: User): Observable<User> {
const headers = new HttpHeaders({
'Authorization': 'Bearer token',
'Content-Type': 'application/json'
});
return this.http.post<User>(this.apiUrl, user, { headers });
}
4.3 表单数据 #
typescript
import { HttpParams } from '@angular/common/http';
login(credentials: LoginCredentials): Observable<AuthResponse> {
const body = new HttpParams()
.set('username', credentials.username)
.set('password', credentials.password);
return this.http.post<AuthResponse>(`${this.apiUrl}/login`, body, {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded'
})
});
}
4.4 FormData上传 #
typescript
uploadFile(file: File): Observable<UploadResponse> {
const formData = new FormData();
formData.append('file', file);
formData.append('description', '文件描述');
return this.http.post<UploadResponse>(`${this.apiUrl}/upload`, formData);
}
五、PUT请求 #
typescript
updateUser(id: number, user: User): Observable<User> {
return this.http.put<User>(`${this.apiUrl}/${id}`, user);
}
updateUserPartial(id: number, changes: Partial<User>): Observable<User> {
return this.http.patch<User>(`${this.apiUrl}/${id}`, changes);
}
六、DELETE请求 #
typescript
deleteUser(id: number): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/${id}`);
}
deleteUserWithResponse(id: number): Observable<HttpResponse<any>> {
return this.http.delete(`${this.apiUrl}/${id}`, {
observe: 'response'
});
}
七、错误处理 #
7.1 基本错误处理 #
typescript
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl).pipe(
catchError(this.handleError)
);
}
private handleError(error: HttpErrorResponse) {
let errorMessage = '发生未知错误';
if (error.error instanceof ErrorEvent) {
errorMessage = `客户端错误: ${error.error.message}`;
} else {
switch (error.status) {
case 400:
errorMessage = '请求参数错误';
break;
case 401:
errorMessage = '未授权,请登录';
break;
case 403:
errorMessage = '拒绝访问';
break;
case 404:
errorMessage = '请求的资源不存在';
break;
case 500:
errorMessage = '服务器内部错误';
break;
default:
errorMessage = `服务器错误: ${error.status}`;
}
}
return throwError(() => new Error(errorMessage));
}
7.2 服务中统一处理 #
typescript
@Injectable({ providedIn: 'root' })
export class ApiService {
private baseUrl = 'https://api.example.com';
constructor(private http: HttpClient) {}
get<T>(url: string, params?: any): Observable<T> {
return this.http.get<T>(`${this.baseUrl}${url}`, { params }).pipe(
retry(3),
catchError(this.handleError)
);
}
post<T>(url: string, body: any): Observable<T> {
return this.http.post<T>(`${this.baseUrl}${url}`, body).pipe(
catchError(this.handleError)
);
}
put<T>(url: string, body: any): Observable<T> {
return this.http.put<T>(`${this.baseUrl}${url}`, body).pipe(
catchError(this.handleError)
);
}
delete<T>(url: string): Observable<T> {
return this.http.delete<T>(`${this.baseUrl}${url}`).pipe(
catchError(this.handleError)
);
}
private handleError(error: HttpErrorResponse) {
return throwError(() => error);
}
}
八、请求重试 #
8.1 使用retry #
typescript
import { retry, retryWhen, delay, scan } from 'rxjs/operators';
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl).pipe(
retry(3)
);
}
// 指数退避重试
getUsersWithBackoff(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl).pipe(
retryWhen(errors =>
errors.pipe(
scan((acc, error) => {
if (acc >= 3) {
throw error;
}
return acc + 1;
}, 0),
delay(1000)
)
)
);
}
九、完整服务示例 #
typescript
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, retry, map } from 'rxjs/operators';
interface User {
id: number;
name: string;
email: string;
}
interface PaginatedResponse<T> {
data: T[];
total: number;
page: number;
size: number;
}
@Injectable({ providedIn: 'root' })
export class UserService {
private apiUrl = 'https://api.example.com/users';
constructor(private http: HttpClient) {}
getUsers(page = 1, size = 10, name?: string): Observable<PaginatedResponse<User>> {
let params = new HttpParams()
.set('page', page.toString())
.set('size', size.toString());
if (name) {
params = params.set('name', name);
}
return this.http.get<PaginatedResponse<User>>(this.apiUrl, { params }).pipe(
retry(2),
catchError(this.handleError)
);
}
getUser(id: number): Observable<User> {
return this.http.get<User>(`${this.apiUrl}/${id}`).pipe(
catchError(this.handleError)
);
}
createUser(user: Omit<User, 'id'>): Observable<User> {
return this.http.post<User>(this.apiUrl, user).pipe(
catchError(this.handleError)
);
}
updateUser(id: number, user: Partial<User>): Observable<User> {
return this.http.put<User>(`${this.apiUrl}/${id}`, user).pipe(
catchError(this.handleError)
);
}
patchUser(id: number, changes: Partial<User>): Observable<User> {
return this.http.patch<User>(`${this.apiUrl}/${id}`, changes).pipe(
catchError(this.handleError)
);
}
deleteUser(id: number): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/${id}`).pipe(
catchError(this.handleError)
);
}
searchUsers(query: string): Observable<User[]> {
return this.http.get<User[]>(`${this.apiUrl}/search`, {
params: { q: query }
}).pipe(
catchError(this.handleError)
);
}
private handleError(error: HttpErrorResponse) {
let errorMessage = '发生未知错误';
if (error.error instanceof ErrorEvent) {
errorMessage = `客户端错误: ${error.error.message}`;
} else {
errorMessage = `服务器错误: ${error.status} - ${error.message}`;
}
console.error('HTTP错误:', error);
return throwError(() => new Error(errorMessage));
}
}
十、在组件中使用 #
typescript
import { Component, OnInit } from '@angular/core';
import { UserService } from '../services/user.service';
import { finalize } from 'rxjs/operators';
@Component({
selector: 'app-user-list',
template: `
<div *ngIf="loading">加载中...</div>
<div *ngIf="error" class="error">{{ error }}</div>
<ul *ngIf="!loading && !error">
<li *ngFor="let user of users">
{{ user.name }} - {{ user.email }}
</li>
</ul>
`
})
export class UserListComponent implements OnInit {
users: User[] = [];
loading = false;
error: string | null = null;
constructor(private userService: UserService) {}
ngOnInit() {
this.loadUsers();
}
loadUsers() {
this.loading = true;
this.error = null;
this.userService.getUsers()
.pipe(
finalize(() => this.loading = false)
)
.subscribe({
next: (response) => {
this.users = response.data;
},
error: (err) => {
this.error = err.message;
}
});
}
}
十一、总结 #
| 方法 | 说明 |
|---|---|
get() |
GET请求 |
post() |
POST请求 |
put() |
PUT请求 |
patch() |
PATCH请求 |
delete() |
DELETE请求 |
head() |
HEAD请求 |
options() |
OPTIONS请求 |
request() |
通用请求方法 |
下一步:HTTP拦截器
最后更新:2026-03-26