激動(dòng)人心的 Angular HttpClient的源碼解析
Angular 4.3.0-rc.0 版本已經(jīng)發(fā)布🐦。在這個(gè)版本中,我們等到了一個(gè)令人興奮的新功能 - HTTPClient API 的改進(jìn)版本,以后媽媽再也不用擔(dān)心我處理 HTTP 請(qǐng)求了😆。
HttpClient 是已有 Angular HTTP API 的演進(jìn),它在一個(gè)單獨(dú)的 @angular/common/http 包中。這是為了確保現(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)
攔截器允許我們將中間件邏輯插入管線中。
請(qǐng)求攔截器 (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>>;
}
需要注意的是,請(qǐng)求對(duì)象和響應(yīng)對(duì)象必須是不可修改的 (immutable)。因此,我們在返回請(qǐng)求對(duì)象前,我們需要克隆原始的請(qǐng)求對(duì)象。
next.handle(req) 方法使用新的請(qǐng)求對(duì)象,調(diào)用底層的 XHR 對(duì)象,并返回響應(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) 返回的流對(duì)象 (即 Observable 對(duì)象) 上應(yīng)用附加的 Rx 操作符來轉(zhuǎn)換響應(yīng)事件流對(duì)象。
接下來要應(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)建請(qǐng)求對(duì)象時(shí),我們需要配置 {reportProgress: true} 參數(shù)。
此外在回調(diào)函數(shù)中,我們通過 event.type 來判斷不同的事件類型,從進(jìn)行相應(yīng)的事件處理。
HttpEventType 枚舉定義如下:
export enum HttpEventType {
/**
* 表示請(qǐng)求已經(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)體訪問,包括對(duì) JSON 響應(yīng)體類型的支持。
最后我們來通過 client_spec.ts 文件中的測試用例,來進(jìn)一步感受一下上述的新特性。
其它特性
發(fā)送 GET 請(qǐng)求
describe('HttpClient', () => {
let client: HttpClient = null !;
let backend: HttpClientTestingBackend = null !;
beforeEach(() => {
backend = new HttpClientTestingBackend();
client = new HttpClient(backend);
});
afterEach(() => { backend.verify(); }); // 請(qǐng)求驗(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 請(qǐng)求
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 請(qǐng)求
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)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Angular.js 實(shí)現(xiàn)數(shù)字轉(zhuǎn)換漢字實(shí)例代碼
這篇文章主要介紹了Angular.js 實(shí)現(xiàn)數(shù)字轉(zhuǎn)換漢字實(shí)例代碼的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
Angularjs自定義指令實(shí)現(xiàn)分頁插件(DEMO)
由于最近的一個(gè)項(xiàng)目使用的是angularjs1.0的版本,涉及到分頁查詢數(shù)據(jù)的功能,后來自己就用自定義指令實(shí)現(xiàn)了該功能,下面小編把實(shí)例demo分享到腳本之家平臺(tái),需要的朋友參考下2017-09-09
angular $watch 一個(gè)變量的變化(實(shí)例講解)
下面小編就為大家?guī)硪黄猘ngular $watch 一個(gè)變量的變化(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08
angularJS實(shí)現(xiàn)動(dòng)態(tài)添加,刪除div方法
下面小編就為大家分享一篇angularJS實(shí)現(xiàn)動(dòng)態(tài)添加,刪除div方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-02-02

