溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

激動人心的 Angular HttpClient的源碼解析

發(fā)布時間:2020-09-16 10:39:55 來源:腳本之家 閱讀:271 作者:semlinker 欄目:web開發(fā)

Angular 4.3.0-rc.0 版本已經發(fā)布🐦。在這個版本中,我們等到了一個令人興奮的新功能 - HTTPClient API 的改進版本,以后媽媽再也不用擔心我處理 HTTP 請求了😆。

HttpClient 是已有 Angular HTTP API 的演進,它在一個單獨的 @angular/common/http 包中。這是為了確?,F有的代碼庫可以緩慢遷移到新的 API。

接下來讓我們開啟 Angular 新版Http Client 之旅。

安裝

首先,我們需要更新所有的包到 4.3.0-rc.0 版本。然后,我們需要在 AppModule 中導入 HttpClientModule 模塊。具體如下:

import { HttpClientModule } from '@angular/common/http';
@NgModule({
 declarations: [
  AppComponent
 ],
 imports: [
  BrowserModule,
  HttpClientModule
 ],
 bootstrap: [AppComponent]
})
export class AppModule { }

現在一切準備就緒。讓我們來體驗一下我們一直期待的三個新特性。

特性一 默認 JSON 解析

現在 JSON 是默認的數據格式,我們不需要再進行顯式的解析。即我們不需要再使用以下代碼:

http.get(url).map(res => res.json()).subscribe(...)

現在我們可以這樣寫:

http.get(url).subscribe(...)

特性二 支持攔截器 (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),我們需要實現 HttpInterceptor 接口,然后實現該接口中的 intercept 方法。

export interface HttpInterceptor {
 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>;
}

需要注意的是,請求對象和響應對象必須是不可修改的 (immutable)。因此,我們在返回請求對象前,我們需要克隆原始的請求對象。

next.handle(req) 方法使用新的請求對象,調用底層的 XHR 對象,并返回響應事件流。

響應攔截器 (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;
   }
  }
}

響應攔截器可以通過在 next.handle(req) 返回的流對象 (即 Observable 對象) 上應用附加的 Rx 操作符來轉換響應事件流對象。

接下來要應用 JWTInterceptor 響應攔截器的最后一件事是注冊該攔截器,即使用 HTTP_INTERCEPTORS 作為 token,注冊 multi Provider:

[{ provide: HTTP_INTERCEPTORS, useClass: JWTInterceptor, multi: true }]

特性三 進度事件 (Progress Events)

進度事件可以用于跟蹤文件上傳和下載。

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);
 }
})

如果我們想要跟蹤文件上傳或下載的進度,在創(chuàng)建請求對象時,我們需要配置 {reportProgress: true} 參數。

此外在回調函數中,我們通過 event.type 來判斷不同的事件類型,從進行相應的事件處理。

HttpEventType 枚舉定義如下:

export enum HttpEventType {
 /**
  * 表示請求已經被發(fā)送
  */
 Sent,

 /**
  * 已接收到上傳進度事件
  */
 UploadProgress,

 /**
  * 已接收到響應狀態(tài)碼和響應頭
  */
 ResponseHeader,

 /**
  * 已接收到下載進度事件
  */
 DownloadProgress,

 /**
  * 已接收全部響應,包含響應體 
  */
 Response,

 /**
  * 用戶自定義事件,來自攔截器或后端
  */
 User,
}

其實除了上面介紹三個新的功能之外,還有以下兩個新的功能:

  1. 基于 Angular 內部測試框架的 Post-request verification 和 flush 功能
  2. 類型化,同步響應體訪問,包括對 JSON 響應體類型的支持。

最后我們來通過 client_spec.ts 文件中的測試用例,來進一步感受一下上述的新特性。

其它特性

發(fā)送 GET 請求

describe('HttpClient', () => {
  let client: HttpClient = null !;
  let backend: HttpClientTestingBackend = null !;
  beforeEach(() => {
   backend = new HttpClientTestingBackend();
   client = new HttpClient(backend);
  });
  afterEach(() => { backend.verify(); }); // 請求驗證
 
  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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI