对 Python 返回 JSON 作为字符串而不是文字感到困惑

Posted

技术标签:

【中文标题】对 Python 返回 JSON 作为字符串而不是文字感到困惑【英文标题】:Confused by Python returning JSON as string instead of literal 【发布时间】:2013-11-12 02:35:29 【问题描述】:

我在 RoR 和 Rails 中完成了一些编码,当我通过 API 调用返回 JSON 对象时,它返回为

"id" : "1", "name" : "Dan"

但是在 Python(使用 Flask 和 Flask-SQLAlchemy)中,当我通过 json.dumps 或 jsonpickle.encode 返回 JSON 对象时,它会返回为

" \"id\" : \"1\", \"name\": \"Dan\" " 看起来非常笨拙,因为它在另一端不容易被解析(在这种情况下由 ios 应用程序 - Obj-C)。

我在这里遗漏了什么,我应该怎么做才能将它作为 JSON 文字而不是 JSON 字符串返回?

这是我的代码的样子:

people = models.UserRelationships.query.filter_by(user_id=user_id, active=ACTIVE_RECORD)
friends = people.filter_by(friends=YES)

json_object = jsonpickle.encode(friends.first().as_dict(), unpicklable=False, keys=True)
print(json_object)  # this prints here, i.e.  "id" : "1", "name" : "Dan" 

return json_object # this returns " \"id\" : \"1\", \"name\": \"Dan\" " to the browser

【问题讨论】:

json.dumps 将返回对象的字符串表示形式。请参阅帮助(json.dumps)-> 将 obj 序列化为 JSON 格式的 str 如果你想要JSON,你应该使用相关模块序列化为JSON。打印一些东西不会把它变成 JSON。 一个 JSON 文字 is 一个字符串。 JSON 是一种表示法。 JSON 只能是一个字符序列。您将数据结构与其表示混淆了。 你显示的代码不可能做你声称的事情。 json_object = print(json_object) 会将 json_object 设置为 None 是的,你是对的。我写代码太快了!对不起。我在上面编辑过。问题是当我将它返回到浏览器时,而不是当我打印它时。 【参考方案1】:

您的理解中缺少的是,当您在 Python 中使用 JSON 模块时,您不是在使用 JSON 对象。 JSON 根据定义只是一个符合特定标准的字符串。

假设你有字符串:

friends = '"name": "Fred", "id": 1'

如果你想在 python 中处理这些数据,你需要将它加载到一个 python 对象中:

import json
friends_obj = json.loads(friends)

此时friends_obj是一个python字典。

如果你想转换它(或任何其他 python 字典或列表),那么这就是 json.dumps 派上用场的地方:

friends_str = json.dumps(friends_obj)
print friends_str
'"name": "Fred", "id": 1'

但是,如果我们尝试“转储”原始朋友字符串,您会看到不同的结果:

dumped_str = json.dumps(friends)
print dumped_str
'"\\"name\\": \\"Fred\\", \\"id\\": 1"'

这是因为您基本上是在尝试将普通字符串编码为 JSON,并且它正在转义字符。我希望这有助于理解事情!

干杯

【讨论】:

谢谢,问题不在于打印。打印时没问题,当我将它返回给浏览器时,它是双重编码的。即return json_object # this returns " \"id\" : \"1\", \"name\": \"Dan\" " 到浏览器【参考方案2】:

看起来您在这里使用 Django,在这种情况下,请执行类似的操作

from django.utils import simplejson as json
...
return HttpResponse(json.dumps(friends.first().as_dict()))

【讨论】:

我没有使用Django,所以我想我不能使用HttpResponse?我正在使用 Python、Flask、Flask-SQLAlchemy.. 啊,对不起,我草率下结论;一些语法看起来像 Django 但不是。 Django 是模块化的,因此您可以根据需要使用一些部分,但如果您使用的是 Flask,则可能不需要。【参考方案3】:

这几乎总是表明您在某处对数据进行了双重编码。例如:

>>> obj =  "id" : "1", "name" : "Dan" 
>>> j = json.dumps(obj)
>>> jj = json.dumps(j)
>>> print(obj)
'id': '1', 'name': 'Dan'
>>> print(j)
"id": "1", "name": "Dan"
>>> print(jj)
"\"id\": \"1\", \"name\": \"Dan\""

这里,jj 是一个完全有效的 JSON 字符串表示形式——但它不是 obj 的表示形式,它是字符串 j 的表示形式,这是没有用的。

通常你不会直接这样做;相反,要么你从一个 JSON 字符串而不是一个对象开始(例如,你从客户端请求或文本文件中获取它),要么你调用了库中的某个函数,如 requestsjsonpickle使用已编码的字符串隐式调用json.dumps。但无论哪种方式,都是同一个问题,但解决方案相同:只是不要双重编码。

【讨论】:

我在 Flask-SQLAlchemy 行上使用 jsonpickle.encode,该行已转换为 dict(即jsonpickle.encode(friends.first().as_dict(), unpicklable=False, keys=True)),因此除非我误解了某些内容,否则它可能还不是编码字符串。 @Dan:你从什么地方退回来的?您的应用程序是如何配置的?如果 Flask 期望你给它一个它将编码的对象,而你正在编码一个对象并给它结果字符串,它最终会被双重编码。 @Dan:顺便说一句,你为什么使用jsonpickle 而不是stdlib json 模块,或者Flask 的内置jsonifyjsonpickle 的全部意义在于,它为您提供了一种包装和解包不直接映射到 JSON 的 Python 类型(如自定义类)的方法,除非对方也使用 jsonpickle,否则这是无用的,这是网络浏览器或 ObjC 应用显然不是。 你是对的。那是我的问题:/我应该一直在使用 jsonify。【参考方案4】:

您应该使用flask.jsonify,它不仅会正确编码,还会相应地设置content-type 标头。

people = models.UserRelationships.query.filter_by(user_id=user_id, active=ACTIVE_RECORD)
friends = people.filter_by(friends=YES)

return jsonify(friends.first().as_dict())

【讨论】:

谢谢!我的问题是无法理解 http 响应和 JSON 字符串之间的区别。将它用于 API 时,我正在关注 http 响应。

以上是关于对 Python 返回 JSON 作为字符串而不是文字感到困惑的主要内容,如果未能解决你的问题,请参考以下文章

jQuery Ajax 调用返回 JSON 字符串而不是对象数组

通过 Node Express 将对象作为字符串而不是 JSON 发送

如何为未经授权的 AJAX 调用而不是登录页面返回 JSON 响应作为 AJAX 响应?

pandas to_json 返回一个字符串而不是 json 对象

PHP:从数据库中返回 JSON 内容而不是字符串 [重复]

PHP json_encode将行作为对象而不是数组返回[重复]