手机版

JSON正确用法探讨:Pyhong、MongoDB、JavaScript、Ajax

时间:2021-10-30 来源:互联网 编辑:宝哥软件园 浏览:

关于这篇文章

本文主要总结了网站建站以来在传输JSON数据时遇到的一些问题以及目前采用的解决方案。网站采用MongoDB,后端采用Python,前端采用“半分离”形式的Riot.js。所谓半分离,就是通过服务器端的模板引擎将第一页数据直接渲染成HTML,避免了两次加载主页的问题,而其他动态内容则由Ajax加载。在整个过程中,数据是以JSON格式传输的,但是在不同的环节需要不同的方式,遇到了一些不同的问题。本文主要是记录和总结。

1.什么是JSON?

JSON(JavaScript Object notification)是由道格拉斯克洛克福特构思和设计的一种轻量级数据交换语言,它的前身XML可能更早就广为人知。当然,JSON并不是为了替代XML而存在的,但是它比XML更小,更适合web开发中的数据传输(JSON之于JavaScript,就像XML之于Lisp一样)。从名字可以看出,JSON的格式符合JavaScript语言中“对象”的语法格式。除了JavaScript,许多其他语言也有类似的类型,比如Python中的dict。除了编程语言,一些基于文档存储的NoSQL非关系数据库也选择JSON作为数据存储格式,比如MongoDB。

一般来说,JSON定义了一种标签格式,可以很容易地在编程语言中转换变量数据和字符串文本数据。JSON描述的数据结构包括以下形式:

对象:{key: value}列表:[obj,obj,]字符串:“字符串”数字:数字布尔值:真/假。

了解了JSON的基本概念后,下面总结了上图中的几个数据交互环节。

2.Python=MongoDB

Python与MongoDB之间的交互主要由现有的驱动库支持,包括Python、Motor等。这些驱动程序提供的界面非常友好。我们不需要知道任何底层实现,只需要操作Python的原始字典类型:

import motor客户端=motor.motor_tornado。motor client()db=client[' test ']user _ col=db[' user ']user _ col . insert(dict(name=' Yu ',is_admin=True,))唯一需要注意的是,MongoDB中的index item _id是由objectid(' 572 df 0b 78 a 83851 d5f 24 e2c 1 ')存储的,对应的Python对象是bson.objectid.ObjectId,所以需要用这个对象的一个实例进行查询:

from bson . ObjectId import ObjectId user=db . user . find _ one(dict(_ id=ObjectId(' 572 df 0b 78 a 83851 D5 f 24 e 2 C1 '))3。Python=Ajax

当遇到第一个坑时,前端和后端之间的数据通信通常通过Ajax完成。在之前的一篇文章中,我总结了Python编码的一个坑。我们知道JSON/XML在HTTP传输过程中肯定是不存在的,一切都是二进制数据。但是,我们可以选择如何让前端解释这些数据,也就是通过在Header中设置Content-Type。一般JSON数据在传输时设置为内容类型:application/JSON。在最新版本的Tornado中,您只需要直接编写字典类型:

# handler async def post(self): user=awa ows . db . user . find _ one({ })self . write(user)随后迎来第一个错误:type error 3360 objectid(' 572 df 0b 58 a 83851 D5 f 24 e 2 b 1 ')不是JSON可序列化的。追溯原因,虽然Tornado为我们简化了操作,但是在编写像HTTP这样的字典类型时,还是需要经过json.dumps(用户)操作,对于json.dumps,ObjectId类型是非法的。所以我选择了最直观的解决方案:

从bson.objectid导入json导入objectid类JSONEncoder(json。JSONEncoder): def def default(self,obj):if isinstance(obj,ObjectId): return str(obj)return super()。default(self,Obj)# handler async def post(self): user=awa自体. db . user . find _ one({ })self . write(jsonencoder . encode(user))这次不会出错。我们自己的JSON编码器可以应付ObjectId,但是也出现了另一个问题:

在JSONEncoder.encode之后,字典类型被转换成字符串,写入HTTP之后,Content-Type变成了text/html。此时,前端会将接收到的数据视为字符串,而不是可用的JavaScript对象。当然,还有一个更进一步的补救办法,那就是前端会再次转换:

$.post(API,{},function(RES){ data=JSON . parse(RES);console.log(数据。_ id);})问题暂时解决,整个过程中JSON的转化如下:

Python==JSON。dumps==http==JavaScript==JSON . parsedict==str==binary==string==object。于是,第二个问题来了。当数据中有一些特殊字符时,JSON。解析将有一个错误:

JSON . parse(' { ' ABS ' : ' \ n ' } ');//vm536:1不清楚的语法错误: JSON中位置1 (…)的意外token’,意思是遇到问题的时候,我们只关注解决眼前的错误和后续的一系列变化带来的弊端。让我们追踪上面的JSON转换链,看看是否有更好的解决方案。很简单,遵循传统规则,当有特殊情况时,改变自己的自适应规则,而不是改变规则:

# handler async def post(self): user=awa自体. db . user . find _ one({ })user[' _ id ']=str(user[' _ id '])self。write (user)当然,如果是多条数据的列表,则需要进一步修改:

# DBasync def get_top_users(self,n=20): users=[]async for user in self . db . user . find({ })。排序(' rank ',-1)。limit(n): user[' id ']=str(user[' id '])users . append(user)返回user 4。Python=HTML Riot.js

如果上述问题可以通过遵循规则来解决,那么下一个问题就是一个挑战规则的故事。除了Ajax动态加载,网页上的其他数据都是由后端模板引擎呈现的,这意味着它是用HTML进行硬编码的。在浏览器加载和解析这个HTML文件之前,它们只是纯文本文件,但是我们需要的是直接插入数据。当浏览器运行JavaScript时,只有脚本标签直接可用。严格来说,这不是JSON的应用,而是Python的dict和JavaScript的Object之间的直接转换。常规方法应该写成如下:

# Handlerasync def get(self): users=self . db . get _ top _ users()render _ data=dict(users=users)self . render(' users . html ',**render_data)!- HTML Riot.js - app/app脚本riot.mount('app ',{ user s :[{ % for user in user % } { name : ' { user[' name ']} } ',Is _ admin : ' { user[' Is _ admin ']} ' } ' },{%end%}],})/脚本是正确的,但是要解决上面提到的ObjectId()问题,还是需要一些额外的处理(尤其是引号)。此外,为了解决ObjectId问题,我还尝试了一个相当愚蠢的方法(在JSON.parse遇到上面的错误之前):

# Handlerasync def get(self): users=self . db . get _ top _ users()render _ data=dict(users=jsonencoder . encode(users))self . render(' users . html ',**render_data)!-html riot . js-app/app script riot . mount(' app ',{ users 3360 JSON . parse(' { { users } } '),})/script其实和第3节的问题是一样的,模板引擎渲染过程和HTTP传输过程类似。不同的是,字符串变量在模板中是纯值(没有引号),因此您可以以生成JavaScript脚本文件的形式呈现变量,而无需担心特殊字符(以下{% raw.%}是Tornado模板用来防止特殊符号被HTML编码的语法):

!-html riot . js-app/appscriptiriot . mount(' app ',{ users: { % rawusers % }),})/脚本摘要。

JSON是一种非常有用的数据格式,但是在不同语言环境之间切换时,还是有很多细节需要注意。此外,遵循传统规则,当有特殊情况时,改变自己的自适应规则,而不是试图改变它们。这条规则可能不适合所有问题,但不要轻易挑战那些已经被认可的规则。

以上是边肖介绍的JSON正确用法的讨论:Pyhong、MongoDB、JavaScript、Ajax。希望对大家有帮助。如果你想了解更多信息,请关注我们的网站!

版权声明:JSON正确用法探讨:Pyhong、MongoDB、JavaScript、Ajax是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。