HttpClient
基本概念
在建構需要與儲存在文件或資料庫中的數據進行交互的 Angular 應用時,重要的一點是,你不會直接與資料庫對話(You don't directly talk to a database),而是透過 API 發送 HTTP 請求,並接收回應。
Angular 提供了 HttpClient
服務來處理這些 HTTP 請求,它是 Angular 應用中與後端服務通訊的標準方式。
設置 HttpClient
步驟 1: 注入 HttpClient
在組件或服務中注入 HttpClient:
import { HttpClient } from '@angular/common/http';
// 使用 inject 函數 (Angular 14+)
private httpClient = inject(HttpClient);
// 或使用建構函數注入
constructor(private httpClient: HttpClient) {}
步驟 2: 提供 HttpClient 服務
如果整個應用程式都需要使用 HttpClient,通常在 main.ts
中全域提供:
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { provideHttpClient } from '@angular/common/http';
bootstrapApplication(AppComponent, {
providers: [provideHttpClient()],
}).catch((err) => console.error(err));
對於使用 NgModule 的傳統應用,在 AppModule 中引入 HttpClientModule:
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],
bootstrap: [AppComponent]
})
export class AppModule {}
發送 HTTP 請求
HttpClient 提供了多種方法來發送不同類型的 HTTP 請求。所有這些方法都返回 Observable,這意味著它們是非同步的。
GET 請求
用於從伺服器獲取資料:
// 基本 GET 請求
this.httpClient.get('https://api.example.com/items').subscribe({
next: (data) => console.log('成功獲取數據:', data),
error: (error) => console.error('發生錯誤:', error)
});
// 使用類型參數的 GET 請求
interface Item {
id: number;
name: string;
}
this.httpClient.get<Item[]>('https://api.example.com/items').subscribe({
next: (items) => {
// items 已經是 Item[] 類型
console.log(`獲取了 ${items.length} 個項目`);
}
});
POST 請求
用於向伺服器發送數據:
const newItem = { name: '新項目', value: 42 };
this.httpClient.post('https://api.example.com/items', newItem).subscribe({
next: (response) => console.log('項目已創建:', response),
error: (error) => console.error('創建失敗:', error)
});
PUT 請求
用於更新伺服器上的資源:
const updatedItem = { id: 1, name: '更新的項目', value: 99 };
this.httpClient.put(`https://api.example.com/items/${updatedItem.id}`, updatedItem).subscribe({
next: (response) => console.log('項目已更新:', response),
error: (error) => console.error('更新失敗:', error)
});
DELETE 請求
用於刪除伺服器上的資源:
const itemId = 1;
this.httpClient.delete(`https://api.example.com/items/${itemId}`).subscribe({
next: () => console.log('項目已刪除'),
error: (error) => console.error('刪除失敗:', error)
});
處理請求選項
HttpClient 方法接受一個選項物件作為第二個參數,可以用來設定各種請求配置:
this.httpClient.get('https://api.example.com/items', {
headers: {
'Authorization': 'Bearer token123',
'Content-Type': 'application/json'
},
params: {
'sort': 'asc',
'page': '1'
},
observe: 'response', // 獲取完整 HTTP 回應,包括標頭
responseType: 'json' // 預設值
}).subscribe({
next: (response) => console.log('完整回應:', response),
error: (error) => console.error('請求失敗:', error)
});
錯誤處理
使用 RxJS 的 catchError
運算符可以更優雅地處理 HTTP 請求錯誤:
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
this.httpClient.get('https://api.example.com/items')
.pipe(
catchError(error => {
console.error('發生錯誤:', error);
// 可以在這裡進行錯誤處理,例如顯示通知或重新導向
return throwError(() => new Error('請求失敗'));
})
)
.subscribe({
next: (data) => console.log('數據:', data)
});
HTTP 攔截器 (Interceptors)
HTTP 攔截器可以用來統一處理所有請求和回應,例如添加認證標頭、記錄請求或處理錯誤:
// auth.interceptor.ts
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(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// 獲取 token(從本地儲存或服務)
const token = localStorage.getItem('token');
// 如果有 token,添加到請求標頭
if (token) {
const authReq = request.clone({
headers: request.headers.set('Authorization', `Bearer ${token}`)
});
return next.handle(authReq);
}
return next.handle(request);
}
}
然後在 providers 中註冊攔截器:
import { provideHttpClient, withInterceptors } from '@angular/common/http';
// 在 main.ts 中
bootstrapApplication(AppComponent, {
providers: [
provideHttpClient(
withInterceptors([authInterceptor])
)
],
});
最佳實踐
創建專用的服務:將 HTTP 請求邏輯封裝在專用的服務中,而不是直接在組件中使用 HttpClient
使用類型:總是為 HTTP 請求和回應指定類型,以獲得更好的類型安全性
取消請求:使用 RxJS 的
takeUntil
運算符來取消不再需要的請求,避免記憶體洩漏將 API URL 放在環境配置:不要在程式碼中硬編碼 API URL,而是使用環境配置
優雅地處理錯誤:實現全域錯誤處理機制,提供一致的用戶體驗
// data.service.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, catchError, throwError } from 'rxjs';
import { environment } from '../environments/environment';
interface Item {
id: number;
name: string;
}
@Injectable({
providedIn: 'root'
})
export class DataService {
private httpClient = inject(HttpClient);
private apiUrl = environment.apiUrl + '/items';
getItems(): Observable<Item[]> {
return this.httpClient.get<Item[]>(this.apiUrl)
.pipe(
catchError(this.handleError)
);
}
getItem(id: number): Observable<Item> {
return this.httpClient.get<Item>(`${this.apiUrl}/${id}`)
.pipe(
catchError(this.handleError)
);
}
createItem(item: Omit<Item, 'id'>): Observable<Item> {
return this.httpClient.post<Item>(this.apiUrl, item)
.pipe(
catchError(this.handleError)
);
}
private handleError(error: any) {
console.error('API 錯誤:', error);
return throwError(() => new Error('請求失敗,請稍後再試'));
}
}
Last updated