JSON 中的大整数被 Angular 而不是 CURL 损坏?

Posted

技术标签:

【中文标题】JSON 中的大整数被 Angular 而不是 CURL 损坏?【英文标题】:Big Integer in JSON getting corrupted by Angular but not by CURL? 【发布时间】:2016-10-19 20:01:34 【问题描述】:

我使用Django Rest Framework 创建了一个 Django REST API。

我使用 3 个不同的客户端来点击这个应用程序:

Curl(用于调试目的) Swagger 接口(用于调试目的) 我的 Angular 应用程序

我有一个令人困惑的问题,即 API 返回的数据被 Swagger 和 Angular 而不是 Curl 损坏。

我的 Django 模型如下所示:

class MyModel1(CachingMixin, models.Model):
    id = models.BigIntegerField(default=make_id, primary_key=True)
    name = models.CharField(max_length=50, null=False, blank=False,)

上面引用的make_id() 方法描述为here。我最近从标准 Django 分配和自动递增的主键实现了这一更改。作为该更改的一部分,我将 id 从 IntegerField 转换为 BigIntegerField

我还有一些其他的 Django 视图代码(我没有在这里显示)创建一个名为 GetMyModel1ByName 的端点。该端点返回MyModel1 的序列化实例。这是显示当我到达那个端点时会发生什么的卷曲。效果很好:

$ curl http://localhost:4212/api/getMyModel1ByName/?name=my-name
"id": 10150133855458395, "name": "my-name"

现在,当我从 Chrome 的开发者控制台点击相同的端点时会发生什么:

> $http = angular.element(document.body).injector().get('$http');
> $http.get("http://localhost:4212/api/getMyModel1ByName/?name=my-name").then(function(response)  console.log(JSON.stringify(response.data)) ).catch(function (error)  console.log(error.data) );
"id":10150133855458396, "name":"my-name"

您可以看到 curl 将 ID 报告为 10150133855458395。这是正确的。这就是数据库中的内容。然而 Angular 将其报告为 10150133855458396。最后一个数字是错误的。差别是1。很惊喜!

这是一个真正令人困惑的错误。我的 Django 代码非常简单,我非常确信其中没有错误。相反,我觉得将id 字段从IntegerField 更改为BigIntegerField 可能会导致此问题。为什么会发生,解决方案是什么?它破坏了我的应用程序的功能。当我通过 Swagger 访问此端点时,我看到了同样的损坏。

编辑: 另一个提问者遇到了同样的问题。很高兴知道我不是唯一一个!然而,关于这个问题的答案并不是真正的答案。他们没有解释原因。他们没有告诉我应该如何解决我的 Angular JS 代码中的问题。

【问题讨论】:

JsonResponse from Django - Incorrect values displayed的可能重复 @middlestump 谢谢!这个问题和我的差不多。很高兴知道我并不孤单。但是那里没有解决我的问题的实际答案。 如果您只是通过浏览器访问http://localhost:4212/api/getMyModel1ByName/?name=my-name 会怎样?同样的错误?如果您再次尝试 Angular 代码但取出 JSON.stringify 怎么办? @jDo,删除 JSON.stringify 没有任何区别。 @rfkortekaas 这与 python 无关。这纯粹是客户端。 【参考方案1】:

您正在尝试存储的数字大于安全的最大 javascript 整数 value(+/- 9007199254740991)

您的 make_id 生成器应返回与 javascript 限制相关的值。

更多信息请阅读: http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html

【讨论】:

OP 在 cmets 中写道 “当我通过浏览器(Chrome 或 Firefox)简单地访问 localhost:4212/api/getMyModel1ByName/?name=my-name 时,我得到了损坏的ID:"id":10150133855458396, "name":"my-name""这不是说即使不涉及JavaScript,ID也是错误的吗? curl 是您可以信任的唯一来源。所有浏览器表示都可以使用 javascript。 确实如此。 curl 和 wget 比任何浏览器都更值得信赖。我只是不希望浏览器在不主动请求(通过编码)的情况下将响应解析为 JSON。无论如何,这可能是这里发生的事情 - 可能是通过扩展/附加组件或一些内置的浏览器魔术自动尝试转换数值和溢出。 ID 应该是一个字符串开头。 是的!另见类似问题:***.com/questions/1379934/…【参考方案2】:

TLDR

长话短说。让您的视图将响应作为字符串返回。

"id": "10150133855458395", "name": "我的名字"

长篇大论

让我们缩小范围。事实上,你可以而且应该在没有 django 参与的情况下进行测试。请将您从curl http://localhost:4212/api/getMyModel1ByName/?name=my-name 获得的 json 保存到您的 django 项目的 /static/ 文件夹中。现在,当您获取它时,django 不再参与图片。您甚至可以将此文件托管在其他类型的服务器上。我们称之为 hello.json

现在如果你输入http://localhost:4212/static/hello.json,你应该会得到。

"id": 10150133855458395, "name": "my-name"

更新:

如果您没有正确看到 JSON 数据,则表示您遇到了Q&A in the first comment 中描述的问题。你有一个狡猾的扩展,它弄乱了 JSON。禁用所有扩展,然后重试。一一启用。

现在让我们创建一个小角度脚本。

<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>

  <div ng-app="myApp" ng-controller="myCtrl">

    <h1>myjson</h1>

  </div>


<script>
   var app = angular.module('myApp', []);
   app.controller('myCtrl', function($scope, $http) 
   $http.get("/static/hello.json")
     .then(function(response) 
        console.log(response.data)
        $scope.myjson = response.data;
      );
   );
</script>

</body>
</html>

然后将其保存为 angular.html 在您的静态文件夹中,您可以在浏览器中将其加载为 http://localhost:4212/static/angular.html 显示。

"id":10150133855458396,"name":"my-name"

这绝对不是正确的结果。但是没有BigIntegerField,这里也没有django。问题完全在于浏览器和角度。我们设法缩小了问题的范围。从浏览器检索的响应中可以看出,它完全在角度范围内。

Angular 对大量数据感到窒息。而是将它们作为字符串发送。

【讨论】:

令人窒息的并不是太多的棱角。它是 JavaScript。它没有单独的整数类型。它只有一个 Number 类型,它存储为浮点值。 谢谢。我会尽快实施。假设它有效,我会标记它正确,我会标记这个答案正确。 很遗憾,浏览器/Javascript/Angular 在处理无法识别的大整数时没有抛出错误或警告。

以上是关于JSON 中的大整数被 Angular 而不是 CURL 损坏?的主要内容,如果未能解决你的问题,请参考以下文章

从 Python 中的大字符串中删除编码的 HTML 标记

日期只输入一个整数而不是C中的日月年

我可以使用啥来获取整数输入而不是 C 中的 scanf?

将JSON中的大数字解析为字符串[重复]

Json 中的 Angular 2 参考

基于范围的大括号初始化器而不是非常量值?