2.8HTTP 客户端 (HttpClient)


文档摘要

2.8HTTP 客户端 (HttpClient) 2.8 HTTP 客户端 (HttpClient) Angular 的 模块提供了一种简化的方式,用于从 Angular 应用程序向服务器发出 HTTP 请求。它是 API 的现代替代品,提供了更强的类型安全、可观察对象支持以及更易于使用的 API。 2.8.1 引入 HttpClient 模块 首先,需要在 Angular 模块中导入 。通常,在 中导入一次就足够了,这样应用程序中的所有组件和服务都可以使用 。 2.8.2 注入 HttpClient 服务 导入 后,就可以在组件或服务中注入 服务了。 2.8.3 发起 HTTP 请求 提供了多种方法来发起不同类型的 HTTP 请求,包括 、 、 、 、 和 。

2.8HTTP 客户端 (HttpClient)

2.8 HTTP 客户端 (HttpClient)

Angular 的 HttpClient 模块提供了一种简化的方式,用于从 Angular 应用程序向服务器发出 HTTP 请求。它是 XMLHttpRequest API 的现代替代品,提供了更强的类型安全、可观察对象支持以及更易于使用的 API。

2.8.1 引入 HttpClient 模块

首先,需要在 Angular 模块中导入 HttpClientModule。通常,在 AppModule 中导入一次就足够了,这样应用程序中的所有组件和服务都可以使用 HttpClient

import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; // 导入 HttpClientModule import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule // 将 HttpClientModule 添加到 imports 数组 ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

2.8.2 注入 HttpClient 服务

导入 HttpClientModule 后,就可以在组件或服务中注入 HttpClient 服务了。

import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class DataService { private apiUrl = 'https://jsonplaceholder.typicode.com/todos'; // 示例 API URL constructor(private http: HttpClient) { } // 注入 HttpClient // 获取所有 ToDos getTodos(): Observable<any[]> { return this.http.get<any[]>(this.apiUrl); } // 获取单个 Todo getTodo(id: number): Observable<any> { return this.http.get<any>(`${this.apiUrl}/${id}`); } // 创建新的 Todo createTodo(todo: any): Observable<any> { return this.http.post<any>(this.apiUrl, todo); } // 更新 Todo updateTodo(id: number, todo: any): Observable<any> { return this.http.put<any>(`${this.apiUrl}/${id}`, todo); } // 删除 Todo deleteTodo(id: number): Observable<any> { return this.http.delete<any>(`${this.apiUrl}/${id}`); } }

2.8.3 发起 HTTP 请求

HttpClient 提供了多种方法来发起不同类型的 HTTP 请求,包括 getpostputdeletepatchhead。 所有这些方法都返回一个 Observable,这意味着你需要订阅它才能接收响应。

2.8.3.1 GET 请求

get 方法用于从服务器检索数据。

import { Component, OnInit } from '@angular/core'; import { DataService } from './data.service'; @Component({ selector: 'app-root', template: ` <ul> <li *ngFor="let todo of todos">{{ todo.title }}</li> </ul> `, styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { todos: any[] = []; constructor(private dataService: DataService) { } ngOnInit(): void { this.dataService.getTodos().subscribe( (data) => { this.todos = data; }, (error) => { console.error('Error fetching todos:', error); } ); } }

2.8.3.2 POST 请求

post 方法用于向服务器发送数据以创建新资源。

// 在 DataService 中 createTodo(todo: any): Observable<any> { return this.http.post<any>(this.apiUrl, todo); } // 在 Component 中 addTodo() { const newTodo = { title: 'New Todo', completed: false }; this.dataService.createTodo(newTodo).subscribe( (data) => { this.todos.push(data); // 添加到本地数组 }, (error) => { console.error('Error creating todo:', error); } ); }

2.8.3.3 PUT 请求

put 方法用于向服务器发送数据以替换现有资源。

// 在 DataService 中 updateTodo(id: number, todo: any): Observable<any> { return this.http.put<any>(`${this.apiUrl}/${id}`, todo); } // 在 Component 中 updateExistingTodo(todo: any) { todo.title = 'Updated Todo'; this.dataService.updateTodo(todo.id, todo).subscribe( (data) => { // 更新本地数组中的 todo }, (error) => { console.error('Error updating todo:', error); } ); }

2.8.3.4 DELETE 请求

delete 方法用于从服务器删除资源。

// 在 DataService 中 deleteTodo(id: number): Observable<any> { return this.http.delete<any>(`${this.apiUrl}/${id}`); } // 在 Component 中 deleteExistingTodo(id: number) { this.dataService.deleteTodo(id).subscribe( (data) => { // 从本地数组中删除 todo this.todos = this.todos.filter(todo => todo.id !== id); }, (error) => { console.error('Error deleting todo:', error); } ); }

2.8.4 处理响应

HttpClient 返回的 Observable 发出三种可能的值:

  • 数据: 成功响应时,Observable 将发出响应主体。

  • 错误: 如果请求失败,Observable 将发出一个错误。

  • 完成: 请求完成后,Observable 将完成。

可以使用 subscribe 方法来处理这些值。

this.dataService.getTodos().subscribe( (data) => { // 处理成功响应 this.todos = data; }, (error) => { // 处理错误 console.error('Error fetching todos:', error); }, () => { // 请求完成 console.log('Todos fetched successfully!'); } );

2.8.5 使用管道 (Pipes) 操作响应

可以使用 RxJS 管道操作符来转换和处理 HttpClient 返回的 Observable。 常用的管道操作符包括 mapfiltercatchErrortap

import { map, catchError } from 'rxjs/operators'; import { of } from 'rxjs'; // 在 DataService 中 getTodos(): Observable<any[]> { return this.http.get<any[]>(this.apiUrl).pipe( map(todos => { // 对 todos 进行一些转换 return todos.map(todo => ({ ...todo, title: todo.title.toUpperCase() })); }), catchError(error => { console.error('Error fetching todos:', error); return of([]); // 返回一个空数组,防止程序崩溃 }) ); }

2.8.6 设置请求头

可以使用 HttpHeaders 类来设置 HTTP 请求头。

import { HttpHeaders } from '@angular/common/http'; // 在 DataService 中 createTodo(todo: any): Observable<any> { const headers = new HttpHeaders({ 'Content-Type': 'application/json', 'Authorization': 'Bearer my-auth-token' }); return this.http.post<any>(this.apiUrl, todo, { headers }); }

2.8.7 处理错误

处理 HTTP 请求错误非常重要,以确保应用程序的健壮性。 可以使用 catchError 管道操作符来捕获错误并执行适当的操作。

import { throwError } from 'rxjs'; // 在 DataService 中 getTodos(): Observable<any[]> { return this.http.get<any[]>(this.apiUrl).pipe( catchError(error => { console.error('Error fetching todos:', error); return throwError(() => new Error('Something bad happened; please try again later.')); // 重新抛出错误 }) ); } // 在 Component 中 this.dataService.getTodos().subscribe( (data) => { this.todos = data; }, (error) => { alert(error.message); // 显示错误信息 } );

2.8.8 使用拦截器 (Interceptors)

HTTP 拦截器允许你拦截和修改 HTTP 请求和响应。 它们可以用于添加身份验证头、日志记录请求、处理错误等。

import { Injectable } from '@angular/core'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable() export class AuthInterceptor implements HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // 克隆请求并添加新的头 const authReq = req.clone({ headers: req.headers.set('Authorization', 'Bearer my-auth-token') }); // 将克隆的请求传递给下一个处理程序 return next.handle(authReq); } }

要使用拦截器,需要在 AppModule 中将其注册为提供程序:

import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { AuthInterceptor } from './auth.interceptor'; @NgModule({ ... providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true } ], ... }) export class AppModule { }

2.8.9 类型安全

HttpClient 提供了类型安全的 API,可以使用泛型来指定响应的类型。 这可以帮助你在编译时捕获错误。

interface Todo { id: number; title: string; completed: boolean; } // 在 DataService 中 getTodos(): Observable<Todo[]> { return this.http.get<Todo[]>(this.apiUrl); }

2.8.10 HttpClient 的工作流程图

graph TD A[Component/Service] --> B(HttpClient.get/post/put/delete); B --> C{Server}; C -->|Response| B; B -->|Observable| D[Component/Service - Subscribe]; D --> E{Process Data}; E --> F[UI Update];

流程说明:

  • A (Component/Service): 组件或服务发起 HTTP 请求。

  • B (HttpClient.get/post/put/delete): 使用 HttpClient 的方法 (例如 get, post, put, delete) 发送请求到服务器。

  • C (Server): 服务器接收请求并处理。

  • Response: 服务器返回响应。

  • D (Component/Service - Subscribe): 组件或服务订阅 HttpClient 返回的 Observable 以接收服务器的响应。

  • E (Process Data): 接收到的数据被处理 (例如,转换数据格式,进行错误处理)。

  • F (UI Update): 处理后的数据用于更新用户界面。

2.8.11 代码示例总结

以下代码片段展示了一个完整的例子,包括服务和组件。

data.service.ts:

import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; interface Todo { id: number; title: string; completed: boolean; } @Injectable({ providedIn: 'root' }) export class DataService { private apiUrl = 'https://jsonplaceholder.typicode.com/todos'; constructor(private http: HttpClient) { } getTodos(): Observable<Todo[]> { return this.http.get<Todo[]>(this.apiUrl).pipe( map(todos => { return todos.map(todo => ({ ...todo, title: todo.title.toUpperCase() })); }), catchError(error => { console.error('Error fetching todos:', error); return throwError(() => new Error('Something went wrong.')); }) ); } createTodo(todo: any): Observable<Todo> { const headers = new HttpHeaders({ 'Content-Type': 'application/json' }); return this.http.post<Todo>(this.apiUrl, todo, { headers }).pipe( catchError(error => { console.error('Error creating todo:', error); return throwError(() => new Error('Failed to create todo.')); }) ); } }

app.component.ts:

import { Component, OnInit } from '@angular/core'; import { DataService } from './data.service'; interface Todo { id: number; title: string; completed: boolean; } @Component({ selector: 'app-root', template: ` <h1>Todos</h1> <ul> <li *ngFor="let todo of todos">{{ todo.title }}</li> </ul> <button (click)="addTodo()">Add Todo</button> `, styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { todos: Todo[] = []; constructor(private dataService: DataService) { } ngOnInit(): void { this.loadTodos(); } loadTodos() { this.dataService.getTodos().subscribe( (data) => { this.todos = data; }, (error) => { alert(error.message); } ); } addTodo() { const newTodo = { title: 'My New Todo', completed: false }; this.dataService.createTodo(newTodo).subscribe( (data) => { this.todos.push(data); }, (error) => { alert(error.message); } ); } }

app.module.ts:

import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

这个例子展示了如何使用 HttpClient 从服务器获取数据,显示数据,以及创建新的数据。它还演示了如何处理错误。

通过以上内容,你应该对 Angular 的 HttpClient 模块有了更深入的理解,并能够开始在自己的应用程序中使用它。记住,熟能生巧,多加练习和实践才能真正掌握它。


发布者: 作者: 转发
评论区 (0)
U