阅读新版 Angular 6 HttpClient 快速入门
以前 激动人心的 Angular HttpClient 这篇文章已经介绍过 HttpClient
,今天看到 angular-university 博客中介绍 HttpClient 的文章,内容很详细,我就简单作了整理。有兴趣的话,建议直接阅读 原文。javascript
import {HttpClientModule} from '@angular/common/http'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule {}
须要注意的是,如今 JSON 是默认的数据格式,咱们不须要再进行显式的解析。即咱们不须要再使用如下代码:java
http.get(url).map(res => res.json()).subscribe(...)
如今咱们能够这样写:typescript
http.get(url).subscribe(...)
import {Component, OnInit} from '@angular/core'; import {Observable} from "rxjs/Observable"; import {HttpClient} from "@angular/common/http"; import * as _ from 'lodash'; interface Course { description: string; courseListIcon:string; iconUrl:string; longDescription:string; url:string; } @Component({ selector: 'app-root', template: ` <ul *ngIf="courses$ | async as courses else noData"> <li *ngFor="let course of courses"> {{course.description}} </li> </ul> <ng-template #noData>No Data Available</ng-template> `}) export class AppComponent implements OnInit { courses$: Observable<any>; constructor(private http:HttpClient) {} ngOnInit() { this.courses$ = this.http .get("https://angular-http-guide.firebaseio.com/courses.json") .map(data => _.values(data)) .do(console.log); } }
假设发送 Get 请求时,须要设置对应的查询参数,预期的 URL 地址以下:shell
https://angular-http-guide.firebaseio.com/courses.json?orderBy="$key"&limitToFirst=1
import {HttpParams} from "@angular/common/http"; const params = new HttpParams() .set('orderBy', '"$key"') .set('limitToFirst', "1"); this.courses$ = this.http .get("/courses.json", {params}) .do(console.log) .map(data => _.values(data))
须要注意的是,咱们经过链式语法调用 set()
方法,构建 HttpParams
对象。这是由于 HttpParams
对象是不可变的,经过 set()
方法能够防止该对象被修改。json
每当调用 set()
方法,将会返回包含新值的 HttpParams
对象,所以若是使用下面的方式,将不能正确的设置参数。bootstrap
const params = new HttpParams(); params.set('orderBy', '"$key"') params.set('limitToFirst', "1");
fromString
语法const params = new HttpParams({fromString: 'orderBy="$key"&limitToFirst=1'});
request()
APIconst params = new HttpParams({fromString: 'orderBy="$key"&limitToFirst=1'}); this.courses$ = this.http .request( "GET", "/courses.json", { responseType:"json", params }) .do(console.log) .map(data => _.values(data));
const headers = new HttpHeaders().set("X-CustomHeader", "custom header value"); this.courses$ = this.http .get( "/courses.json", {headers}) .do(console.log) .map(data => _.values(data));
httpPutExample() { const headers = new HttpHeaders().set("Content-Type", "application/json"); this.http.put("/courses/-KgVwECOnlc-LHb_B0cQ.json", { "courseListIcon": ".../main-page-logo-small-hat.png", "description": "Angular Tutorial For Beginners TEST", "iconUrl": ".../angular2-for-beginners.jpg", "longDescription": "...", "url": "new-value-for-url" }, {headers}) .subscribe( val => { console.log("PUT call successful value returned in body", val); }, response => { console.log("PUT call in error", response); }, () => { console.log("The PUT observable is now completed."); } ); }
httpPatchExample() { this.http.patch("/courses/-KgVwECOnlc-LHb_B0cQ.json", { "description": "Angular Tutorial For Beginners PATCH TEST", }) .subscribe( (val) => { console.log("PATCH call successful value returned in body", val); }, response => { console.log("PATCH call in error", response); }, () => { console.log("The PATCH observable is now completed."); }); }
httpDeleteExample() { this.http.delete("/courses/-KgVwECOnlc-LHb_B0cQ.json") .subscribe( (val) => { console.log("DELETE call successful value returned in body", val); }, response => { console.log("DELETE call in error", response); }, () => { console.log("The DELETE observable is now completed."); }); }
httpPostExample() { this.http.post("/courses/-KgVwECOnlc-LHb_B0cQ.json", { "courseListIcon": "...", "description": "TEST", "iconUrl": "..", "longDescription": "...", "url": "new-url" }) .subscribe( (val) => { console.log("POST call successful value returned in body", val); }, response => { console.log("POST call in error", response); }, () => { console.log("The POST observable is now completed."); }); }
duplicateRequestsExample() { const httpGet$ = this.http .get("/courses.json") .map(data => _.values(data)); httpGet$.subscribe( (val) => console.log("logging GET value", val) ); this.courses$ = httpGet$; }
在上面例子中,咱们正在建立了一个 HTTP observable 对象 httpGet$
,接着咱们直接订阅该对象。而后,咱们把 httpGet$
对象赋值给 courses$
成员变量,最后在模板中使用 async
管道订阅该对象。segmentfault
这将致使发送两个 HTTP 请求,在这种状况下,请求显然是重复的,由于咱们只但愿从后端查询一次数据。为了不发送冗余的请求,咱们可使用 RxJS 提供的 shareReplay
操做符:后端
// put this next to the other RxJs operator imports import 'rxjs/add/operator/shareReplay'; const httpGet$ = this.http .get("/courses.json") .map(data => _.values(data)) .shareReplay();
并行发送 HTTP 请求的一种方法是使用 RxJs 中的 forkjoin
操做符:api
import 'rxjs/add/observable/forkJoin'; parallelRequests() { const parallel$ = Observable.forkJoin( this.http.get('/courses/-KgVwEBq5wbFnjj7O8Fp.json'), this.http.get('/courses/-KgVwECOnlc-LHb_B0cQ.json') ); parallel$.subscribe( values => { console.log("all values", values) } ); }
sequentialRequests() { const sequence$ = this.http.get<Course>('/courses/-KgVwEBq5wbFnjj7O8Fp.json') .switchMap(course => { course.description+= ' - TEST '; return this.http.put('/courses/-KgVwEBq5wbFnjj7O8Fp.json', course) }); sequence$.subscribe(); }
sequentialRequests() { const sequence$ = this.http.get<Course>('/courses/-KgVwEBq5wbFnjj7O8Fp.json') .switchMap(course => { course.description+= ' - TEST '; return this.http.put('/courses/-KgVwEBq5wbFnjj7O8Fp.json', course) }, (firstHTTPResult, secondHTTPResult) => [firstHTTPResult, secondHTTPResult]); sequence$.subscribe(values => console.log("result observable ", values) ); }
throwError() { this.http .get("/api/simulate-error") .catch( error => { // here we can show an error message to the user, // for example via a service console.error("error catched", error); return Observable.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...") ); }
当发生异常时,控制台的输出结果:angular2
Error catched HttpErrorResponse {headers: HttpHeaders, status: 404, statusText: "Not Found", url: "http://localhost:4200/api/simulate-error", ok: false, … } Value emitted successfully {description: "Error Value Emitted"} HTTP Observable completed...
import {Injectable} from "@angular/core"; import {HttpEvent, HttpHandler, HttpInterceptor} from "@angular/common/http"; import {HttpRequest} from "@angular/common/http"; import {Observable} from "rxjs/Observable"; @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private authService: AuthService) { } intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const clonedRequest = req.clone({ headers: req.headers.set('X-CustomAuthHeader', authService.getToken()) }); console.log("new headers", clonedRequest.headers.keys()); return next.handle(clonedRequest); } }
@NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [ [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true } ] ], bootstrap: [AppComponent] }) export class AppModule { }
longRequest() { const request = new HttpRequest( "POST", "/api/test-request", {}, {reportProgress: true}); this.http.request(request) .subscribe( event => { if (event.type === HttpEventType.DownloadProgress) { console.log("Download progress event", event); } if (event.type === HttpEventType.UploadProgress) { console.log("Upload progress event", event); } if (event.type === HttpEventType.Response) { console.log("response received...", event.body); } } ); }
上面示例运行后,控制台的可能的输出结果:
Upload progress event Object {type: 1, loaded: 2, total: 2} Download progress event Object {type: 3, loaded: 31, total: 31} Response Received... Object {description: "POST Response"}