[Angular] 利用interceptor 將回傳的Date string 轉做 Date object

在Angular 中, Pipe 就像WPF 中的coverter 般將接到的data 轉換為用作須要用的format顯示出來. 然而在front-end development 中, 從web service 接到的日期, 通常都被當成string 般處理. 若要須要轉成Date, 則需要透過interceptor 收到response, 利用regular expression 轉換成 Date 回傳出來. 在示範中, 會利用HTTP response 的JSON方法如下.json-interceptor.ts

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpResponse, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map';

// https://github.com/angular/angular/blob/master/packages/common/http/src/xhr.ts#L18
const XSSI_PREFIX = /^\)\]\}',?\n/;

/**
 * Provide custom json parsing capabilities for api requests.
 * @export
 * @class JsonInterceptor
 */
@Injectable()
export class JsonInterceptor implements HttpInterceptor {

    /**
     * Custom http request interceptor
     * @public
     * @param {HttpRequest<any>} req
     * @param {HttpHandler} next
     * @returns {Observable<HttpEvent<any>>}
     * @memberof JsonInterceptor
     */
    public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (req.responseType !== 'json') {
            return next.handle(req);
        }
        // convert to responseType of text to skip angular parsing
        req = req.clone({
            responseType: 'text'
        });

        return next.handle(req).map(event => {
            // Pass through everything except for the final response.
            if (!(event instanceof HttpResponse)) {
                return event;
            }
            return this.processJsonResponse(event);
        });
    }

    /**
     * Parse the json body using custom revivers.
     * @private
     * @param {HttpResponse<string>} res
     * @returns{HttpResponse<any>}
     * @memberof JsonInterceptor
     */
    private processJsonResponse(res: HttpResponse<string>): HttpResponse<any> {
        let body = res.body;
        if (typeof body === 'string') {
            const originalBody = body;
            body = body.replace(XSSI_PREFIX, '');
            try {
                body = body !== '' ? JSON.parse(body, (key: any, value: any) => this.reviveUtcDate(key, value)) : null;
            } catch (error) {
                // match https://github.com/angular/angular/blob/master/packages/common/http/src/xhr.ts#L221
                throw new HttpErrorResponse({
                    error: { error, text: originalBody },
                    headers: res.headers,
                    status: res.status,
                    statusText: res.statusText,
                    url: res.url || undefined,
                });
            }
        }
        return res.clone({ body });
    }

    /**
     * Detect a date string and convert it to a date object.
     * @private
     * @param {*} key json property key.
     * @param {*} value json property value.
     * @returns {*} original value or the parsed date.
     * @memberof JsonInterceptor
     */
    private reviveUtcDate(key: any, value: any): any {
        if (typeof value !== 'string') {
            return value;
        }
        if (value === '0001-01-01T00:00:00.000+0000') {
            return null;
        }
        const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})\.(\d{3})[+-](\d{4})$/.exec(value);
        if (!match) {
            return value;
        }
        return new Date(value);
    }
}

app.module 叫用方法:

import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { JsonInterceptor } from '../json-interceptor';
@NgModule({
providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: JsonInterceptor,
      multi: true
    }
  ]
})

 

About C.H. Ling 260 Articles
a .net / Java developer from Hong Kong and currently located in United Kingdom. Thanks for Google because it solve many technical problems so I build this blog as return. Besides coding and trying advance technology, hiking and traveling is other favorite to me, so I will write down something what I see and what I feel during it. Happy reading!!!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


This site uses Akismet to reduce spam. Learn how your comment data is processed.