与Angular 4.3的解析日期HttpClient
我目前正在切换到Angular 4.3的新HttpClient。一个优点是我可以在GET方法中指定一个类型信息,并且返回的JSON被解析为给定的类型,例如,与Angular 4.3的解析日期HttpClient
this.http.get<Person> (url).subscribe(...)
但不幸的是,在所有JSON日期解析为在结果对象编号(可能是因为Java日期对象序列化为数字在后端)。
随着旧的Http我喜欢这个调用JSON.parse()来时使用的齐磊功能:
this.http.get(url)
.map(response => JSON.parse(response.text(), this.reviver))
,并在齐磊功能我创建从数字日期对象:
reviver (key, value): any {
if (value !== null && (key === 'created' || key === 'modified'))
return new Date(value);
return value;
}
是否有与新的HttpClient类似的机制?或者在解析JSON时进行转换的最佳做法是什么?
您可以使用:
this.http.get(url, { responseType: 'text' })
.map(r => JSON.parse(r, this.reviver))
.subscribe(...)
那里似乎不幸的是不要被一个齐磊传递给所内的角度HttpClient的使用JSON.parse方法的一种方式。下面是他们叫其中JSON.parse源代码: https://github.com/angular/angular/blob/20e1cc049fa632e88dfeb00476455a41b7f42338/packages/common/http/src/xhr.ts#L189
角如果响应类型设置为“JSON”(你可以看到这个上线183)将只解析响应。如果您未指定响应类型,则Angular默认为“json”(https://github.com/angular/angular/blob/20e1cc049fa632e88dfeb00476455a41b7f42338/packages/common/http/src/request.ts#L112)。
所以你可以使用“text”的响应类型并自己解析json。或者你可能只是懒惰和序列化,然后反序列化响应(JSON.parse(JSON.stringify(res.body), reviver)
)。
不必修改每一个电话,你可以创建类似下面的拦截器:
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);
}
}
然后,你必须向它提供的模块:
* .module.ts
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { JsonInterceptor } from '...';
@NgModule({
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: JsonInterceptor,
multi: true
}
]
})
...
在这个例子中,我试图模仿角度如何尽可能地进行解析。它们似乎不会导出HttpJsonParseError,因此我无法将错误转换为该类型。这可能不是完美的,但我希望它能得到这个想法。
这里是一个正在运行的例子(看在控制台中看到的日期解析到):https://stackblitz.com/edit/angular-qqbmcx
我创建了一个功能要求在这里: https://github.com/angular/angular/issues/21079
我不相信有没有更好的方式来实现JSON API的日期/时间。 – Ryan
Upvoted我可以。它可以帮助别人知道这个拦截器需要注册才能工作。这个链接帮助我这么做:https://medium.com/@ryanchenkie_40935/angular-authentication-using-the-http-client-and-http-interceptors-2f9d1540eb8 – evilkos
我也发现在注册这个拦截器之后,我的全局错误处理程序停止显示来自有效内容的错误消息,因为错误响应现在不被解析。为了解决这个问题,我需要修改'intercept'方法的结尾,就像'return next.handle(req).catch((e,c)=> {e.error = JSON.parse(e.error); return Observable.throw(e);})。map(event => {...'这只是一个提示,可以明显改善,至少可以恢复日期 – evilkos
你仍然可以,但你需要导入map()
- 运算符这样从rxjs:
import 'rxjs/add/operator/map';
然后你就可以,就像迭戈指出,使用map
这样的:
return this.http.get<BlogPost>(url)
.map(x => {
x.published = new Date(String(x.published));
return x;
})
[...]
难道不可能将这个reviver函数重定位到您期望的对象,即Person? – Laurens
人最有可能是一个接口,所以它没有方法 –