閱讀新版 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"}