angular httpclient 自定义 json 解析器 (jsog)
angular httpclient custom json parser (jsog)
我刚刚发现新的 Angular 4.3.x HttpClient
模块,我很可能忽略了一些简单的东西。
我想知道是否可以注册一个自定义 JSON 反序列化器并仍然获得类型化 HttpClient
get/post/put 的好处。碰巧出于性能原因,我的后端 returns JSOG,它是 JSON 的扩展,而不是 JSON
内容。
目前我使用普通的 get(url, {responseType: 'text'})
发出所有请求,然后 运行 通过 RxJs Map Operation 的响应来转换我想要的 Observable 中的 Observable<string>
,返回 JSOG.parse(responseString)
。
我是否错过了使用某种拦截器的解决方案?非常感谢您的建议。
您可以只实现一个 HttpInterceptor 并拦截响应并在 return 发送给调用者之前根据需要改变正文。
我正在做一些类似于从我的 API 中截取 Microsoft ASP.NET 格式日期 return 并将它们转换为实际 Date 实例的操作。
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpInterceptor, HttpRequest, HttpResponse, HttpErrorResponse, HttpHandler, HttpEvent } from '@angular/common/http';
@Injectable()
export class Interceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).do(event => {
if (event instanceof HttpResponse) {
const resp: HttpResponse<any> = event;
// Mutate the body, replace ASP.NET Dates with actual local Date objects.
let body: {} = resp.body;
this.recurseBody(body);
}
});
}
private recurseBody(body: {}) {
if (!body) {
return;
}
for (let key in body) {
if (body.hasOwnProperty(key)) {
let element = body[key];
if (typeof element === 'object') {
this.recurseBody(element);
} else if (typeof element === 'string') {
// Check for a MS-format Date with optional TZ offset.
const matched = /\/Date\(([-]?\d{1,15})([\+-][01][0-3][0-5][0-9])?\)\//.exec(element);
if (matched) {
let tzOffsetMs = 0;
const tz = matched[2] || '';
if (tz) {
const hours = parseInt(tz.substr(0, tz.length - 2), 10);
const mins = parseInt(tz.substr(tz.length - 2, 2), 10);
const tzOffsetMins = mins + hours * 60;
tzOffsetMs = tzOffsetMins * 60 * 1000;
}
// Create a UTC Date object.
const date = new Date(+matched[1] + tzOffsetMs);
// Get the timezone offset for the local time (in minutes) and convert to ms.
const tzOffset = date.getTimezoneOffset() * 60 * 1000;
// Create a local date by using the offset
const localDate = new Date(date.getTime() + tzOffset);
console.log('convert ' + element + ' to ' + date + ' offset ' + date.getTimezoneOffset() + ' local = ' + localDate);
// Set the local date.
body[key] = localDate;
}
}
}
}
}
}
这是我的解决方案,
@Injectable()
export class JSOGInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (typeof req.body === 'object' && !(req.body instanceof FormData)) {
req = req.clone({body: JSOG.encode(req.body) });
}
return next.handle(req).map(resp => {
if (resp instanceof HttpResponse && typeof resp.body === 'object' && !(resp.body instanceof Blob)) {
resp = resp.clone({ body: JSOG.decode(resp.body) });
}
return resp;
});
}
我刚刚发现新的 Angular 4.3.x HttpClient
模块,我很可能忽略了一些简单的东西。
我想知道是否可以注册一个自定义 JSON 反序列化器并仍然获得类型化 HttpClient
get/post/put 的好处。碰巧出于性能原因,我的后端 returns JSOG,它是 JSON 的扩展,而不是 JSON
内容。
目前我使用普通的 get(url, {responseType: 'text'})
发出所有请求,然后 运行 通过 RxJs Map Operation 的响应来转换我想要的 Observable 中的 Observable<string>
,返回 JSOG.parse(responseString)
。
我是否错过了使用某种拦截器的解决方案?非常感谢您的建议。
您可以只实现一个 HttpInterceptor 并拦截响应并在 return 发送给调用者之前根据需要改变正文。
我正在做一些类似于从我的 API 中截取 Microsoft ASP.NET 格式日期 return 并将它们转换为实际 Date 实例的操作。
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpInterceptor, HttpRequest, HttpResponse, HttpErrorResponse, HttpHandler, HttpEvent } from '@angular/common/http';
@Injectable()
export class Interceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).do(event => {
if (event instanceof HttpResponse) {
const resp: HttpResponse<any> = event;
// Mutate the body, replace ASP.NET Dates with actual local Date objects.
let body: {} = resp.body;
this.recurseBody(body);
}
});
}
private recurseBody(body: {}) {
if (!body) {
return;
}
for (let key in body) {
if (body.hasOwnProperty(key)) {
let element = body[key];
if (typeof element === 'object') {
this.recurseBody(element);
} else if (typeof element === 'string') {
// Check for a MS-format Date with optional TZ offset.
const matched = /\/Date\(([-]?\d{1,15})([\+-][01][0-3][0-5][0-9])?\)\//.exec(element);
if (matched) {
let tzOffsetMs = 0;
const tz = matched[2] || '';
if (tz) {
const hours = parseInt(tz.substr(0, tz.length - 2), 10);
const mins = parseInt(tz.substr(tz.length - 2, 2), 10);
const tzOffsetMins = mins + hours * 60;
tzOffsetMs = tzOffsetMins * 60 * 1000;
}
// Create a UTC Date object.
const date = new Date(+matched[1] + tzOffsetMs);
// Get the timezone offset for the local time (in minutes) and convert to ms.
const tzOffset = date.getTimezoneOffset() * 60 * 1000;
// Create a local date by using the offset
const localDate = new Date(date.getTime() + tzOffset);
console.log('convert ' + element + ' to ' + date + ' offset ' + date.getTimezoneOffset() + ' local = ' + localDate);
// Set the local date.
body[key] = localDate;
}
}
}
}
}
}
这是我的解决方案,
@Injectable()
export class JSOGInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (typeof req.body === 'object' && !(req.body instanceof FormData)) {
req = req.clone({body: JSOG.encode(req.body) });
}
return next.handle(req).map(resp => {
if (resp instanceof HttpResponse && typeof resp.body === 'object' && !(resp.body instanceof Blob)) {
resp = resp.clone({ body: JSOG.decode(resp.body) });
}
return resp;
});
}