本教程将介绍如何在 Angular 6.x 中使用 HttpClient 发送 Http 请求,如 get、post、put 和 delete 请求。在 Angular 4.3+ 版本之后引入了 HttpClientModule 模块,该模块提供的 HttpClient 服务是已有 Angular HTTP API 的演进,它在一个单独的 @angular/common/http
包中。
废话不多说,现在让我们来看一下如何在 Angular 6.x 中使用 HttpClientModule 模块。
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 是默认的数据格式,我们不需要再进行显式的解析。即我们不需要再使用以下代码:
http.get(url).map(res => res.json()).subscribe(...)
现在我们可以这样写:
http.get(url).subscribe(...)
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 地址如下:
https://jsonplaceholder.typicode.com/todos?_page=1&_limit=10
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");
const params = new HttpParams({fromString: "_page=1&_limit=10"});
const params = new HttpParams({ fromObject: { _page: "1", _limit: "10" } });
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 类型。
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));
}
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.");
}
);
}
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.");
}
);
}
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.");
}
);
}
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.");
}
);
}
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);
});
}
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);
});
}
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);
});
}
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...")
);
}
当发生异常时,控制台的输出结果:
Error catched
HttpErrorResponse {headers: HttpHeaders, status: 404, ...}
Value emitted successfully {description: "Error Value Emitted"}
HTTP Observable completed...
auth.interceptor.ts
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);
}
}
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 {}
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);
}
});
}
以上代码成功运行后,在控制台会输出以下信息:
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 请求。