我有 .Net Web API,它将从第三方 API 收到的数据返回给我面向 Angular 应用程序的用户。 当 API 返回像 999,999,999,999,999.99 这样的大数字时,Angular 会将其更改为 10,000,000,000,000,000。我不想四舍五入这个数字,因为它是敏感数据。
我想到了一个解决方法来解决这个问题并保留如此巨大的数字的小数位。解决方法是在将数据发送回 Angular 应用程序之前将数字转换为字符串。有两种方法可以实现这一目标:
使用一些正则表达式,并通过在数字两边加上引号将所有数字字段设为字符串。
目前,在 .NET API 中,我正在以字符串形式读取第三方 API 的响应,并将其放入 ContentString 中,然后再将其发送到 Angular 应用程序。我可以定义一个模型,然后在该模型中将所有数字类型字段定义为字符串,而不是将内容读取为字符串。
我想知道这两种方法哪一种更好。如果有人可以分享一些正确的方法来实现这一目标,我将非常感激。
我认为你可以使用BigJS:
var n = new Big('999999999999999.99');
这是一个 JavaScript 问题,而不是 Angular 特定问题。 JavaScript 数字始终存储为双精度浮点数,遵循国际 IEEE 754 标准。
进一步阅读:
https://www.w3schools.com/js/js_numbers.asp
示例:
(function() {
//1000000000000000
const a = 999999999999999.99
//99999999999999.98
const b = 99999999999999.99
//999999999999999
const c = 999999999999999
//'999999999999999.99'
const d = '999999999999999.99'
console.log(a);
console.log(b);
console.log(c);
console.log(d);
}
)();
我认为您将很难毫无问题地存储大于 999999999999999 的数字。也许最好存储为字符串。
正如其他人指出的,这是 JS 的问题,而不是 Angular 的问题。 JS 中的数字是双精度浮点数,这意味着对于高数字或小数位数很多的数字会失去精度。正如您提到的,您已经在使用 bignumber.js,您似乎意识到了这一事实。
具体来说,当您执行响应类型为
json
的 HTTP 请求时,您通常永远不会真正获得 json 正文中发送的“真实”值。 JSON 字符串将自动解析为 JS 对象,此时已经失去精度。
幸运的是,有一种方法可以防止这种情况发生。在 Angular 中,您可以使用 HttpInterceptor 将响应类型从
json
更改为 text
,并在收到响应后手动解析它。此时,JS 没有对响应执行任何操作,它只是 API 发送到前端的纯字符串,此时不会丢失任何精度。
对于 JSON 解析并将所有
number
转换为 BigNumber
,为了方便起见,我使用 JSONBigNumber 库,但我确信使用标准实用程序也可以轻松实现这一点。
所描述的拦截器的代码如下所示:
@Injectable()
export class BigNumberInterceptor implements HttpInterceptor {
intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return httpRequest.responseType === "json"
? this.handleJsonResponses(httpRequest, next)
: next.handle(httpRequest);
}
private handleJsonResponses(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next
.handle(httpRequest.clone({ responseType: "text" }))
.pipe(
map(response => this.parseResponse(response)),
catchError(response => this.handleErrorResponse(response))
);
}
private parseResponse(response: HttpEvent<any>): HttpEvent<any> {
return response instanceof HttpResponse
? response.clone({ body: this.parseJson(response.body) })
: response;
}
private handleErrorResponse(response: any): Observable<HttpEvent<any>> {
if (response instanceof HttpErrorResponse) {
if (response.error == null) {
throw response;
} else {
throw new HttpErrorResponse({
error: this.parseJson(response.error),
headers: response.headers,
status: response.status,
statusText: response.statusText,
url: response.url ?? undefined
});
}
} else {
throw response;
}
}
private parseJson(jsonBody: string) {
if (!jsonBody) {
return jsonBody;
} else {
try {
return JSONBigNumber.parse(jsonBody);
} catch (e) {
return jsonBody;
}
}
}
}
对于一个简单的任务来说,看起来有很多代码,但这只是因为
HttpErrorResponse
需要单独处理,因为它们当然也包含 JSON 响应。由于拦截器将响应类型更改为 text
,这也适用于错误响应。所以这里也需要手动进行解析。
您还需要为 Angular 的
HTTP_INTERCEPTORS
注入令牌提供此拦截器,以便 Angular 知道它应该使用它。您可以像这样在您的 AppModule
中添加提供商:
@NgModule({
// ...
providers: [
// ...
{
provide: HTTP_INTERCEPTORS,
multi: true,
useClass: BigNumberInterceptor
}
]
})
export class AppModule {
// ...
}