集中處理我們的所有http的request和response處理,並且讓讀取的狀態自動顯示和隱藏
前言
早在angularjs的時候,就有http interceptor的概念,可以讓我們很好的封裝和處理這方面的邏輯,而且也可以使用https://github.com/chieffancypants/angular-loading-bar這個元件,自動就會偵測http的request和response來自動完成loading中的效果,但是angular2並沒有http interceptor的範例,所以筆者就只好自己找找資源來實做一下囉,以下則是一些紀錄
導覽
http interceptor的實做
其實github上面有不少人實做了http interceptor並且open source出來,個人最後選擇了這個版本的https://github.com/voliva/angular2-interceptors,當然首先就是用npm下載下來,然後建立一支http-interceptor.ts
@Injectable()
export class HttpInterceptor implements Interceptor {
queue = 0;
constructor() { }
public interceptBefore(request: InterceptedRequest): InterceptedRequest {
return request;
}
public interceptAfter(response: InterceptedResponse): InterceptedResponse {
return response;
}
}
這樣我們就可以實做任何request和response結果的處理,打個比方如果我想要在request之前,在header做些處理,然後在response收到各種錯誤處理碼然後做些處理的話,我們甚至可以定義各種http回傳的state code的enum來讓程式碼更好讀,先建立一支http-state-code.enum.ts
export enum HttpStateCode {
MultipleChoices = 300,
Redirect = 302,
BadRequest = 400,
Unauthorized = 401,
Forbidden = 403,
NotFound = 404,
NotAcceptable = 406,
RequestTimeout = 408,
RequestUriTooLong = 414,
UnsupportedMediaType = 415,
RequestedRangeNotSatisfiable = 416,
InternalServerError = 500,
ServiceUnavailable = 503
};
接著我們的http interceptor可以改成這樣子
@Injectable()
export class HttpInterceptor implements Interceptor {
constructor() { }
public interceptBefore(request: InterceptedRequest): InterceptedRequest {
request.options.headers.set('Content-Type','application/json');
return request;
}
public interceptAfter(response: InterceptedResponse): InterceptedResponse {
switch (response.response.status) {
case HttpStateCode.InternalServerError:
alert('伺服器故障囉');
break;
}
return response;
}
}
怎麼實做就自由發揮囉,不過我們還必須要把這個service註冊在module裡面,module是要註冊在根module或建立一個新的module就看個人了,在此示例是建立在app.module.ts裡面
export function interceptorFactory(xhrBackend: XHRBackend, requestOptions: RequestOptions, httpInterceptor: HttpInterceptor) {
const service = new InterceptorService(xhrBackend, requestOptions);
service.addInterceptor(httpInterceptor); // Add it here
return service;
}
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
],
providers: [
HttpInterceptor,
{
provide: InterceptorService,
useFactory: interceptorFactory,
deps: [XHRBackend, RequestOptions, HttpInterceptor]
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
因為我們已經實做了這個服務,所以當我們要建立一個http的時候,就要改用我們建立的這個服務,而不是原生的Http囉
constructor(protected http: Http) { }
//改成如下
constructor(protected http: InterceptorService) { }
跟http interceptor整合loading的效果
其實ng2的loading bar有很多選擇,也有自動加載的,我們完全不用控制的,可以參考https://github.com/aitboudad/ng-loading-bar,但我個人整合http interceptor的時候發現有點問題,最後我選擇的是自己控制的,可以參考https://github.com/akserg/ng2-slim-loading-bar,接著就來介紹一下筆者個人的整合和做法了,因為在http的時候,我們可能同時會送出好幾個request和收到好幾個response,所以我們沒辦法單純的在request去開啟loading bar然後在response關閉,所以我定義了一個number,在request去++在response去--,這樣子只要數值是0的話,就代表我們可以關閉loadingbar了,示例如下
@Injectable()
export class HttpInterceptor implements Interceptor {
queue = 0;
constructor(private loadginBar: SlimLoadingBarService) { }
public interceptBefore(request: InterceptedRequest): InterceptedRequest {
this.queue ++;
this.loadginBar.start();
request.options.headers.set('Content-Type', 'application/json');
return request;
}
public interceptAfter(response: InterceptedResponse): InterceptedResponse {
this.queue--;
this.queue===0 && this.loadginBar.stop();
switch (response.response.status) {
case HttpStateCode.InternalServerError:
alert('伺服器故障囉');
break;
}
return response;
}
完成之後我們必須要在moduled import這個module
imports: [
SlimLoadingBarModule.forRoot()
]
結論
angular 2的loading效果其實很多做法,有些人是重覆在每次ajax的時候去控制,我個人選擇是統一集中在http的發起和接收的地方做處理,這樣子要抽換效果就更便利囉。