使用Angular 4.3 HttpClient解析日期 [英] Parse date with Angular 4.3 HttpClient

查看:111
本文介绍了使用Angular 4.3 HttpClient解析日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在切换到Angular 4.3的新HttpClient.一个优点是我可以在GET方法上指定类型信息,并将返回的JSON解析为给定的类型,例如

I'm currently switching to the new HttpClient of Angular 4.3. One advantage is that I can specify a type info on the GET method and that the returned JSON is parsed into the given type, e.g.

this.http.get<Person> (url).subscribe(...)

但是不幸的是,JSON中的所有日期都被解析为结果对象中的数字(可能是因为Java Date对象在后端被序列化为数字).

But unfortunately, all dates in the JSON are parsed as numbers in the resulting object (probably because the Java Date objects are serialized as numbers in the backend).

使用旧的Http时,我在调用JSON.parse()时使用了reviver函数,如下所示:

With the old Http I used a reviver function when calling JSON.parse() like this:

this.http.get(url)
  .map(response => JSON.parse(response.text(), this.reviver))

,在reviver函数中,我从数字创建了日期对象:

and in the reviver function I created date objects from the numbers:

reviver (key, value): any {
  if (value !== null && (key === 'created' || key === 'modified'))
    return new Date(value);

  return value;
}

新的HttpClient是否有类似的机制?还是解析JSON时进行转换的最佳实践是什么?

Is there a similar mechanism with the new HttpClient? Or what is the best practice to do conversion when the JSON is parsed?

推荐答案

不幸的是,似乎没有一种方法可以将reviver传递给Angular HttpClient中使用的JSON.parse方法.这是他们调用JSON.parse的源代码: https://github.com/angular /angular/blob/20e1cc049fa632e88dfeb00476455a41b7f42338/packages/common/http/src/xhr.ts#L189

Unfortunately there doesn't seem to be a way to pass a reviver to the JSON.parse method that is used within the Angular HttpClient. Here is the source code for where they call JSON.parse: https://github.com/angular/angular/blob/20e1cc049fa632e88dfeb00476455a41b7f42338/packages/common/http/src/xhr.ts#L189

只有将响应类型设置为"json",Angular才会解析响应(您可以在第183行上看到它).如果您未指定响应类型,则Angular默认为"json"(

Angular will only parse the response if the response type is set to "json" (you can see this on line 183). If you don't specify the response type then Angular defaults to "json" (https://github.com/angular/angular/blob/20e1cc049fa632e88dfeb00476455a41b7f42338/packages/common/http/src/request.ts#L112).

因此,您可以使用文本"的响应类型并自己解析json.或者,您可以懒惰并序列化然后反序列化响应(JSON.parse(JSON.stringify(res.body), reviver)).

So you could use a response type of "text" and parse the json yourself. Or you could just be lazy and serialize and then deserialize the response (JSON.parse(JSON.stringify(res.body), reviver)).

您可以像下面这样创建拦截器,而不用修改每个呼叫:

Rather than modifying every call you could create an interceptor like the following:

json-interceptor.ts

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpResponse, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Rx';
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') {
          return null;
      }
      const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
      if (!match) {
          return value;
      }
      return new Date(value);
  }
}

然后您必须在模块中提供它:

Then you have to provide it in your module:

*.module.ts

import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { JsonInterceptor } from '...';

@NgModule({
    providers: [
        {
            provide: HTTP_INTERCEPTORS,
            useClass: JsonInterceptor,
            multi: true
        }
    ]
})
...

在该示例中,我试图模仿角度如何尽可能地进行解析.他们似乎没有导出HttpJsonParseError,所以我无法将错误转换为该类型.它可能不是完美的,但我希望它能使想法得到理解.

In the example I tried to mimic how angular was doing the parsing as much as possible. They don't seem to export HttpJsonParseError so I couldn't cast the error to that type. It probably isn't perfect but I hope it gets the idea across.

这是一个正在运行的示例(在控制台中查看以了解解析的日期): https://stackblitz .com/edit/json-interceptor

Here is a running example (look in the console to see the date parsed): https://stackblitz.com/edit/json-interceptor

我在此处创建了功能请求: https://github.com/angular/angular/issues/21079

I created a feature request here: https://github.com/angular/angular/issues/21079

这篇关于使用Angular 4.3 HttpClient解析日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆