激動人心的 Angular HttpClient的源碼解析
Angular 4.3.0-rc.0 版本已經(jīng)發(fā)布🐦。在這個(gè)版本中,我們等到了一個(gè)令人興奮的新功能 - HTTPClient API 的改進(jìn)版本,以后媽媽再也不用擔(dān)心我處理 HTTP 請求了😆。
HttpClient 是已有 Angular HTTP API 的演進(jìn),它在一個(gè)單獨(dú)的 @angular/common/http
包中。這是為了確?,F(xiàn)有的代碼庫可以緩慢遷移到新的 API。
接下來讓我們開啟 Angular 新版Http Client 之旅。
安裝
首先,我們需要更新所有的包到 4.3.0-rc.0
版本。然后,我們需要在 AppModule
中導(dǎo)入 HttpClientModule
模塊。具體如下:
import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule ], bootstrap: [AppComponent] }) export class AppModule { }
現(xiàn)在一切準(zhǔn)備就緒。讓我們來體驗(yàn)一下我們一直期待的三個(gè)新特性。
特性一 默認(rèn) JSON 解析
現(xiàn)在 JSON 是默認(rèn)的數(shù)據(jù)格式,我們不需要再進(jìn)行顯式的解析。即我們不需要再使用以下代碼:
http.get(url).map(res => res.json()).subscribe(...)
現(xiàn)在我們可以這樣寫:
http.get(url).subscribe(...)
特性二 支持?jǐn)r截器 (Interceptors)
攔截器允許我們將中間件邏輯插入管線中。
請求攔截器 (Request Interceptor)
import { HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; @Injectable() class JWTInterceptor implements HttpInterceptor { constructor(private userService: UserService) {} intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const JWT = `Bearer ${this.userService.getToken()}`; req = req.clone({ setHeaders: { Authorization: JWT } }); return next.handle(req); } }
如果我們想要注冊新的攔截器 (interceptor),我們需要實(shí)現(xiàn) HttpInterceptor
接口,然后實(shí)現(xiàn)該接口中的 intercept
方法。
export interface HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>; }
需要注意的是,請求對象和響應(yīng)對象必須是不可修改的 (immutable)。因此,我們在返回請求對象前,我們需要克隆原始的請求對象。
next.handle(req)
方法使用新的請求對象,調(diào)用底層的 XHR 對象,并返回響應(yīng)事件流。
響應(yīng)攔截器 (Response Interceptor)
@Injectable() class JWTInterceptor implements HttpInterceptor { constructor(private router: Router) {} intercept(req: HttpRequest < any > , next: HttpHandler): Observable < HttpEvent < any >> { return next.handle(req).map(event => { if (event instanceof HttpResponse) { if (event.status === 401) { // JWT expired, go to login } } return event; } } }
響應(yīng)攔截器可以通過在 next.handle(req)
返回的流對象 (即 Observable 對象) 上應(yīng)用附加的 Rx 操作符來轉(zhuǎn)換響應(yīng)事件流對象。
接下來要應(yīng)用 JWTInterceptor
響應(yīng)攔截器的最后一件事是注冊該攔截器,即使用 HTTP_INTERCEPTORS
作為 token,注冊 multi Provider:
[{ provide: HTTP_INTERCEPTORS, useClass: JWTInterceptor, multi: true }]
特性三 進(jìn)度事件 (Progress Events)
進(jìn)度事件可以用于跟蹤文件上傳和下載。
import { HttpEventType, HttpClient, HttpRequest } from '@angular/common/http'; http.request(new HttpRequest( 'POST', URL, body, { reportProgress: true })).subscribe(event => { if (event.type === HttpEventType.DownloadProgress) { // { // loaded:11, // Number of bytes uploaded or downloaded. // total :11 // Total number of bytes to upload or download // } } if (event.type === HttpEventType.UploadProgress) { // { // loaded:11, // Number of bytes uploaded or downloaded. // total :11 // Total number of bytes to upload or download // } } if (event.type === HttpEventType.Response) { console.log(event.body); } })
如果我們想要跟蹤文件上傳或下載的進(jìn)度,在創(chuàng)建請求對象時(shí),我們需要配置 {reportProgress: true}
參數(shù)。
此外在回調(diào)函數(shù)中,我們通過 event.type
來判斷不同的事件類型,從進(jìn)行相應(yīng)的事件處理。
HttpEventType
枚舉定義如下:
export enum HttpEventType { /** * 表示請求已經(jīng)被發(fā)送 */ Sent, /** * 已接收到上傳進(jìn)度事件 */ UploadProgress, /** * 已接收到響應(yīng)狀態(tài)碼和響應(yīng)頭 */ ResponseHeader, /** * 已接收到下載進(jìn)度事件 */ DownloadProgress, /** * 已接收全部響應(yīng),包含響應(yīng)體 */ Response, /** * 用戶自定義事件,來自攔截器或后端 */ User, }
其實(shí)除了上面介紹三個(gè)新的功能之外,還有以下兩個(gè)新的功能:
- 基于 Angular 內(nèi)部測試框架的 Post-request verification 和 flush 功能
- 類型化,同步響應(yīng)體訪問,包括對 JSON 響應(yīng)體類型的支持。
最后我們來通過 client_spec.ts 文件中的測試用例,來進(jìn)一步感受一下上述的新特性。
其它特性
發(fā)送 GET 請求
describe('HttpClient', () => { let client: HttpClient = null !; let backend: HttpClientTestingBackend = null !; beforeEach(() => { backend = new HttpClientTestingBackend(); client = new HttpClient(backend); }); afterEach(() => { backend.verify(); }); // 請求驗(yàn)證 describe('makes a basic request', () => { it('for JSON data', (done: DoneFn) => { client.get('/test').subscribe(res => { expect((res as any)['data']).toEqual('hello world'); done(); }); backend.expectOne('/test').flush({'data': 'hello world'}); }); it('for an arraybuffer', (done: DoneFn) => { const body = new ArrayBuffer(4); // 還支持 {responseType: 'text'}、{responseType: 'blob'} client.get('/test', {responseType: 'arraybuffer'}).subscribe(res => { expect(res).toBe(body); done(); }); backend.expectOne('/test').flush(body); }); it('that returns a response', (done: DoneFn) => { const body = {'data': 'hello world'}; client.get('/test', {observe: 'response'}).subscribe(res => { expect(res instanceof HttpResponse).toBe(true); expect(res.body).toBe(body); done(); }); backend.expectOne('/test').flush(body); }); }); });
發(fā)送 POST 請求
describe('makes a POST request', () => { it('with text data', (done: DoneFn) => { client.post('/test', 'text body', {observe: 'response', responseType: 'text'}) .subscribe(res => { expect(res.ok).toBeTruthy(); expect(res.status).toBe(200); done(); }); backend.expectOne('/test').flush('hello world'); }); it('with json data', (done: DoneFn) => { const body = {data: 'json body'}; client.post('/test', body, {observe: 'response', responseType: 'text'}).subscribe(res => { expect(res.ok).toBeTruthy(); expect(res.status).toBe(200); done(); }); const testReq = backend.expectOne('/test'); expect(testReq.request.body).toBe(body); testReq.flush('hello world'); }); });
發(fā)送 JSONP 請求
describe('makes a JSONP request', () => { it('with properly set method and callback', (done: DoneFn) => { client.jsonp('/test', 'myCallback').subscribe(() => done()); backend.expectOne({method: 'JSONP', url: '/test?myCallback=JSONP_CALLBACK'}) .flush('hello world'); }); });
參考資源
A Taste From The New Angular HTTP Client
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
AngularJS中的API(接口)簡單實(shí)現(xiàn)
本文主要介紹AngularJS API(接口),這里對AngularJS API的知識做了詳細(xì)講解,并附簡單代碼實(shí)例,有需要的小伙伴可以參考下2016-07-07AngularJS單選框及多選框?qū)崿F(xiàn)雙向動態(tài)綁定
這篇文章主要為大家詳細(xì)介紹了AngularJS單選框及多選框?qū)崿F(xiàn)雙向動態(tài)綁定的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-01-01angular 基于ng-messages的表單驗(yàn)證實(shí)例
本篇文章主要介紹了angular 基于ng-messages的表單驗(yàn)證實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05AngularJS整合Springmvc、Spring、Mybatis搭建開發(fā)環(huán)境
這篇文章主要介紹了AngularJS整合Springmvc、Spring、Mybatis搭建開發(fā)環(huán)境的相關(guān)資料,為學(xué)習(xí)使用AngularJS做好基礎(chǔ)準(zhǔn)備,感興趣的小伙伴們可以參考一下2016-02-02Angular自定義組件實(shí)現(xiàn)數(shù)據(jù)雙向數(shù)據(jù)綁定的實(shí)例
下面小編就為大家分享一篇Angular自定義組件實(shí)現(xiàn)數(shù)據(jù)雙向數(shù)據(jù)綁定的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12angularjs使用gulp-uglify壓縮后執(zhí)行報(bào)錯(cuò)的解決方法
下面小編就為大家分享一篇angularjs使用gulp-uglify壓縮后執(zhí)行報(bào)錯(cuò)的解決方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03AngularJS折疊菜單實(shí)現(xiàn)方法示例
這篇文章主要介紹了AngularJS折疊菜單實(shí)現(xiàn)方法,結(jié)合完整實(shí)例形式分析了AngularJS實(shí)現(xiàn)折疊菜單的具體步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-05-05