本教程将介绍如何在 Angular 6.x 中使用 HttpClient 发送 Http 请求,如 get、post、put 和 delete 请求。在 Angular 4.3 版本之后引入了 HttpClientModule 模块,该模块提供的 HttpClient 服务是已有 Angular HTTP API 的演进,它在一个单独的 @angular/common/http
包中。
废话不多说,现在让我们来看一下如何在 Angular 6.x 中使用 HttpClientModule 模块。
导入 HttpClientModule 模块
代码语言:javascript复制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 {}
需要注意的是,现在 JSON 是默认的数据格式,我们不需要再进行显式的解析。即我们不需要再使用以下代码:
代码语言:javascript复制http.get(url).map(res => res.json()).subscribe(...)
现在我们可以这样写:
代码语言:javascript复制http.get(url).subscribe(...)
发送 Get 请求
代码语言:javascript复制import { Component, OnInit } from "@angular/core";
import { HttpClient, HttpParams, HttpHeaders } from "@angular/common/http";
import { Observable } from "rxjs";
import { tap } from "rxjs/operators";
interface Todo {
userId: number;
id: number;
title: string;
completed: boolean;
}
@Component({
selector: "app-root",
template: `
<ul *ngIf="todos$ | async as todos else noData">
<li *ngFor="let todo of todos">
<span>Title: {{todo.title}}</span> ——
<span>Completed: {{todo.completed}}</span>
</li>
</ul>
<ng-template #noData>No Data Available</ng-template>
`
})
export class AppComponent implements OnInit {
todos$: Observable<Todo[]>;
constructor(private http: HttpClient) {}
ngOnInit() {
this.todos$ = this.http
.get<Todo[]>(
"https://jsonplaceholder.typicode.com/todos?_page=1&_limit=10"
)
.pipe(tap(console.log));
}
}
设置查询参数
假设发送 Get 请求时,需要设置对应的查询参数,预期的 URL 地址如下:
代码语言:javascript复制https://jsonplaceholder.typicode.com/todos?_page=1&_limit=10
创建 HttpParams 对象
代码语言:javascript复制import { HttpClient, HttpParams } from "@angular/common/http";
const params = new HttpParams().set("_page", "1").set("_limit", "10");
ngOnInit() {
this.todos$ = this.http
.get<Todo[]>("https://jsonplaceholder.typicode.com/todos", { params })
.pipe(tap(console.log));
}
需要注意的是,我们通过链式语法调用 set()
方法,构建 HttpParams
对象。这是因为 HttpParams
对象是不可变的,通过 set()
方法可以防止该对象被修改。
每当调用 set()
方法,将会返回包含新值的 HttpParams
对象,因此如果使用下面的方式,将不能正确的设置参数。
const params = new HttpParams();
params.set("_page", "1")
params.set("_limit", "10");
使用 fromString
代码语言:javascript复制const params = new HttpParams({fromString: "_page=1&_limit=10"});
使用 fromObject
代码语言:javascript复制const params = new HttpParams({ fromObject: { _page: "1", _limit: "10" } });
使用 request API
代码语言:javascript复制ngOnInit() {
this.users$ = this.http
.request("GET", "https://jsonplaceholder.typicode.com/todos", { params })
.pipe(tap(console.log));
}
获取完整响应
默认情况下,HttpClient 服务返回的是响应体,有时候我们需要获取响应头的相关信息,这时你可以设置请求 options 对象的 observe
属性值为 response
来获取完整的响应对象。
this.http.get("https://jsonplaceholder.typicode.com/todos/1", {
observe: "response"
})
.subscribe(res => {
console.dir("Response: " res.status);
});
设置响应类型
如果你期望的响应对象的格式不是 JSON,你可以通过 responseType
属性来设定响应类型,比如:
this.http.get("https://jsonplaceholder.typicode.com/todos/1", {
responseType: "text"
}).subscribe(text => {
console.log("Response: " text);
});
需要注意的是除了支持 json 和 text 类型外,还支持 arraybuffer 和 blob 类型。
设置 Http Headers
代码语言:javascript复制const params = new HttpParams({ fromObject: { _page: "1", _limit: "10" } });
const headers = new HttpHeaders().set("token", "iloveangular");
ngOnInit() {
this.todos$ = this.http
.get<Todo[]>("https://jsonplaceholder.typicode.com/todos", {
headers,
params
})
.pipe(tap(console.log));
}
发送 Put 请求
代码语言:javascript复制const headers = new HttpHeaders().set(
"Content-type",
"application/json; charset=UTF-8"
);
updateFirstTodo() {
this.http
.put(
"https://jsonplaceholder.typicode.com/todos/1",
{
userId: 1,
id: 1,
title: "delectus aut autem",
completed: true
},
{ headers }
)
.subscribe(
val => {
console.log("Put call successful value returned in body", val);
},
error => {
console.log("Put call in error", error);
},
() => {
console.log("The PUT observable is now completed.");
}
);
}
发送 Patch 请求
代码语言:javascript复制const headers = new HttpHeaders().set(
"Content-type",
"application/json; charset=UTF-8"
);
patchFirstTodo() {
this.http
.patch(
"https://jsonplaceholder.typicode.com/todos/1",
{
title: "learn angular 7"
},
{ headers }
)
.subscribe(
val => {
console.log("Patch call successful value returned in body", val);
},
error => {
console.log("Patch call in error", error);
},
() => {
console.log("The Patch observable is now completed.");
}
);
}
发送 Delete 请求
代码语言:javascript复制const headers = new HttpHeaders().set(
"Content-type",
"application/json; charset=UTF-8"
);
deleteFirstTodo() {
this.http
.delete("https://jsonplaceholder.typicode.com/todos/1", {
headers
})
.subscribe(
val => {
console.log("Delete call successful value returned in body", val);
},
error => {
console.log("Delete call in error", error);
},
() => {
console.log("The Delete observable is now completed.");
}
);
}
发送 Post 请求
代码语言:javascript复制const headers = new HttpHeaders().set(
"Content-type",
"application/json; charset=UTF-8"
);
createNewTodo() {
this.http
.post(
"https://jsonplaceholder.typicode.com/todos",
{
userId: 1,
title: "learn ionic 4",
completed: false
},
{ headers }
)
.subscribe(
val => {
console.log("Post call successful value returned in body", val);
},
error => {
console.log("Post call in error", error);
},
() => {
console.log("The Post observable is now completed.");
}
);
}
并行发送多个 Http 请求
代码语言:javascript复制parallelRequests() {
const parallel$ = forkJoin(
this.http.get("https://jsonplaceholder.typicode.com/users/1"),
this.http.get("https://jsonplaceholder.typicode.com/todos/1")
);
parallel$.subscribe(values => {
console.log("all values", values);
});
}
顺序发送 Http 请求
代码语言:javascript复制sequentialRequests() {
const sequence$ = this.http
.get<Todo>("https://jsonplaceholder.typicode.com/todos/1")
.pipe(
switchMap(todo => {
todo.title = " - TEST ";
return this.http.put("https://jsonplaceholder.typicode.com/todos/1", todo);
})
);
sequence$.subscribe(val => {
console.log("Put call successful value returned in body", val);
});
}
获取顺序发送 Http 请求的结果
代码语言:javascript复制sequentialRequests() {
const sequence$ = this.http
.get<Todo>("https://jsonplaceholder.typicode.com/todos/1")
.pipe(
switchMap(
todo => {
const newTitle = todo.title " - TEST ";
const newTodo = { ...todo, title: newTitle };
return this.http.put(
"https://jsonplaceholder.typicode.com/todos/1",
newTodo
);
},
(firstHTTPResult, secondHTTPResult) => [
firstHTTPResult,
secondHTTPResult
]
)
);
sequence$.subscribe(val => {
console.log("Put call successful value returned in body", val);
});
}
请求异常处理
代码语言:javascript复制import { of } from "rxjs";
import { catchError } from "rxjs/operators";
throwError() {
this.http
.get("https://jsonplaceholder.typicode.com/simulate-error")
.pipe(
catchError(error => {
console.error("Error catched", error);
return of({ description: "Error Value Emitted" });
})
)
.subscribe(
val => console.log("Value emitted successfully", val),
error => {
console.error("This line is never called ", error);
},
() => console.log("HTTP Observable completed...")
);
}
当发生异常时,控制台的输出结果:
代码语言:javascript复制Error catched
HttpErrorResponse {headers: HttpHeaders, status: 404, ...}
Value emitted successfully {description: "Error Value Emitted"}
HTTP Observable completed...
Http 拦截器
定义拦截器
auth.interceptor.ts
代码语言:javascript复制import { Injectable } from "@angular/core";
import { HttpEvent, HttpRequest, HttpHandler, HttpInterceptor } from "@angular/common/http";
import { Observable } from "rxjs";
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const clonedRequest = req.clone({
headers: req.headers.set("X-CustomAuthHeader", "iloveangular")
});
console.log("new headers", clonedRequest.headers.keys());
return next.handle(clonedRequest);
}
}
应用拦截器
代码语言:javascript复制import { AuthInterceptor } from "./interceptors/auth.interceptor";
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, HttpClientModule],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule {}
Http 进度事件
代码语言:javascript复制getData() {
this.http
.get("https://jsonplaceholder.typicode.com/todos", {
observe: 'events',
reportProgress: true
})
.subscribe((event: HttpEvent<any>) => {
switch (event.type) {
case HttpEventType.Sent:
console.log("Request sent!");
break;
case HttpEventType.ResponseHeader:
console.log("Response header received!");
break;
case HttpEventType.DownloadProgress:
const kbLoaded = Math.round(event.loaded / 1024);
console.log(`Download in progress! ${kbLoaded}Kb loaded`);
break;
case HttpEventType.Response:
console.log("Done!", event.body);
}
});
}
以上代码成功运行后,在控制台会输出以下信息:
代码语言:javascript复制Request sent!
Response header received!
Download in progress! 6Kb loaded
Download in progress! 24Kb loaded
Done!
总结
本文通过 jsonplaceholder 提供的 API,介绍了如何使用 HttpClientModule 模块中的 HttpClient 服务,发送 Get、Post、Delete 等请求,同时介绍了如何利用 RxJS 处理并行和顺序 Http 请求。