亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

JSON 的正確用法探討:Pyhong、MongoDB、JavaScript與Ajax

2019-11-20 10:03:18
字體:
來源:轉載
供稿:網友

關于本文

本文主要總結網站編寫以來在傳遞 JSON 數據方面遇到的一些問題以及目前采用的解決方案。網站數據庫采用 MongoDB,后端是 Python,前端采用“半分離”形式的 Riot.js,所謂半分離,是說第一頁數據是通過服務器端的模板引擎直接渲染到 HTML 中,從而避免首頁兩次加載的問題,而其它動態內容則采用 Ajax 加載。整個流程中數據都是通過 JSON 格式傳遞的,但是在不同的環節中需要采用不同的方式并遇到一些不同的問題,本文主要做記錄、總結。

1. What is JSON?

JSON(JavaScript Object Notation) 是一種由道格拉斯?克羅克福特構想設計、輕量級的數據交換語言,它的前輩 XML 可能更早被人們所熟知。當然 JSON 并不是為了取代 XML 而存在的,只是相比于 XML 它更小巧、更適合在網頁開發中用作數據傳遞(JSON 之于 JavaScript 就像 XML 之于 Lisp)。從名字上可以看出,JSON 的格式符合 JavaScript 語言中“對象”的語法格式,除了 JavaScript 之外,很多其他語言中也具有類似的類型,例如 Python 中的字典( dict ),除了編程語言之外,一些基于文檔存儲的 NoSQL 非關系型數據庫也選擇 JSON 作為其數據存儲格式,例如 MongoDB。

總的來說,JSON 定義一種標記格式,可以非常方便地在編程語言中的變量數據與字符串文本數據之間相互轉換。JSON 描述的數據結構包括以下這幾種形式:

對象: {key: value}
列表: [obj, obj,...]
字符串: "string"
數字:數字
布爾值: true / false

了解了 JSON 的基本概念之后,下面分別針對上圖中的幾個數據交互環節進行總結。

2. Python <=> MongoDB

Python 與 MongoDB 之間的交互主要由現有的驅動庫提供支持,包括 PyMongo、Motor 等,而這些驅動所提供的接口都是非常友好的,我們不需要了解任何底層的實現,只要對 Python 原生的字典類型進行操作即可:

import motor client = motor.motor_tornado.MotorClient() db = client['test']user_col = db['user'] user_col.insert(dict( name = 'Yu',is_admin = True,))

唯一需要注意的是 MongoDB 中的索引項 _id 是通過 ObjectId("572df0b78a83851d5f24e2c1") 存儲的,而對應的 Python 對象為 bson.objectid.ObjectId ,因此在查詢時需要以此對象的實例進行:

from bson.objectid import ObjectId user = db.user.find_one(dict( _id = ObjectId("572df0b78a83851d5f24e2c1")))

3. Python <=> Ajax

前端與后端之間的數據交流比較常用的是通過 Ajax 完成,這時遇到了第一個不大不小的坑。在之前的一篇文章中,我總結了 一次 Python 編碼的坑 ,我們知道 HTTP 傳遞過程中肯定不存在 JSON/XML ,一切都是二進制數據,但是我們可以選擇讓前端用什么樣的方式解讀這些數據,即通過設定 Header 中的 Content-Type ,一般傳遞 JSON 數據時將其設定為 Content-Type: application/json ,在 Tornado 最新版本中,只需要直接寫入字典類型即可:

# Handlerasync def post(self): user = await self.db.user.find_one({})self.write(user)

于是迎來了第一個錯誤: TypeError: ObjectId('572df0b58a83851d5f24e2b1') is not JSON serializable 。追溯原因,雖然 Tornado 幫我們簡化了操作,但在像 HTTP 中寫入字典類型時仍然需要經歷一次 json.dumps(user) 操作,而對于 json.dumps 來說, ObjectId 類型是非法的。于是我選擇了最直觀的解決方案:

import json from bson.objectid import ObjectId class JSONEncoder(json.JSONEncoder): def default(self, obj):if isinstance(obj, ObjectId):return str(obj)return super().default(self, obj)# Handlerasync def post(self): user = await self.db.user.find_one({})self.write(JSONEncoder.encode(user))

這次不會再出錯了,我們自己的 JSONEncoder 可以應對 ObjectId 了,但另一個問題也出現了:

JSONEncoder.encode 之后字典類型被轉換成字符串,寫入 HTTP 之后 Content-Type 變為 text/html ,這時前端將認為接收的數據為字符串而不是可用的 JavaScript Object。當然還有進一步的彌補方案,那就是前端再進行一次轉換:

$.post(API, {}, function(res){data = JSON.parse(res);console.log(data._id);})

問題暫時解決了,在整個過程中 JSON 的變換是這樣的:

Python ==> json.dumps ==> HTTP ==> JavaScript ==> JSON.parse dict ==> str ==> binary ==> string ==> Object 

結果第二個問題來了,當數據中存在一些特殊字符時, JSON.parse 將出現錯誤:

JSON.parse("{'abs': '/n'}"); // VM536:1 Uncaught SyntaxError: Unexpected token ' in JSON at position 1(…)

這就是在遇到問題是只著眼解決眼前錯誤導致后續一連串改動所帶來的弊病。我們沿著上面 JSON 變換的鏈條向上追溯,看有沒有更好的解決方案。很簡單, 遵循傳統規則,出現特例的時候,改變自身適應規則,而不是改變規則 :

# Handlerasync def post(self): user = await self.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({}).sort('rank', -1).limit(n):user['_id'] = str(user['_id'])users.append(user)return users

4. Python <=> HTML+Riot.js

如果上面的問題可以通過 遵守規則 來解決,那么接下來這個問題就是一個挑戰規則的故事。除去 Ajax 動態加載部分,網頁上的其他數據是通過后端模板引擎渲染得來的,也就是說是 Hard-coding 為 HTML 的。在瀏覽器加載并解析這個 HTML 文件之前它們只是純文本文件,而我們需要的是直接將數據塞僅 <script> 標簽在瀏覽器運行 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> <script> riot.mount('app', {users: [{% for user in users %}{ name: "{{ user['name']}}", is_admin: "{{ user['is_admin']}}" },{% end %}],})</script> 

這樣寫是對的,但是要解決上面提到的 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: JSON.parse('{{ users }}'),})</script> 

其實跟第 3 小節的問題一樣,模板引擎渲染過程與 HTTP 傳輸過程是類似的,不同的是在模板中字符串變量就是純粹的值(沒有引號),因此完全可以用生成 JavaScript 腳本文件的形式渲染變量而無需顧慮特殊字符(下面的 {% raw ... %} 是 Tornado 模板用于防止特殊符號被 HTML 編碼的語法):

<!-- HTML + Riot.js --> <app></app> <script> riot.mount('app', {users: {% raw users %}),})</script> 

總結

JSON 是很好用的數據格式,但是在不同語言環境之間切換還是有很多細節問題需要注意。此外, 遵循傳統規則,出現特例的時候,改變自身適應規則,而不是試圖改變規則 ,這一條不一定適應所有問題,但對于那些已被公認的規則,請勿輕易挑戰。

以上所述是小編給大家介紹的JSON 的正確用法探討:Pyhong、MongoDB、JavaScript與Ajax的相關知識,希望對大家有所幫助,如果大家想了解更多資訊敬請關注武林網網站!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人激情视频在线| 欧美极品少妇xxxxⅹ喷水| 日韩精品在线私人| 中文字幕精品在线视频| 久久99视频精品| 久久精品国产69国产精品亚洲| 这里只有视频精品| 美女久久久久久久久久久| 成人妇女免费播放久久久| 亚洲欧美日韩中文在线制服| 亚洲男人的天堂网站| 国产日韩欧美在线观看| 亚洲精品国偷自产在线99热| 亚洲欧美精品伊人久久| 日韩精品在线视频观看| 成人免费淫片aa视频免费| 久久影视电视剧免费网站清宫辞电视| 狠狠操狠狠色综合网| 色偷偷噜噜噜亚洲男人| 97视频在线观看免费| 影音先锋欧美精品| 日韩精品中文字幕在线| 国产一区二区三区精品久久久| 久久国产加勒比精品无码| 国产丝袜精品视频| 日韩欧美在线视频| www高清在线视频日韩欧美| 日本免费一区二区三区视频观看| 在线亚洲男人天堂| 日韩免费在线电影| 青青草99啪国产免费| 欧美激情啊啊啊| 538国产精品视频一区二区| 91视频国产精品| 亚洲美女在线看| 在线播放国产精品| 久久777国产线看观看精品| 国产精品免费福利| 国产精品扒开腿做爽爽爽的视频| 色婷婷综合久久久久中文字幕1| 亚洲а∨天堂久久精品喷水| 国产成人精品一区| 北条麻妃99精品青青久久| 国产精品人成电影在线观看| 国产精品av免费在线观看| 最近2019年中文视频免费在线观看| 亚洲网站视频福利| 亚洲欧洲国产一区| 精品欧美aⅴ在线网站| 国产欧美日韩精品专区| 中文字幕日韩专区| 亚洲一区国产精品| 91av视频导航| 一区二区三欧美| 日韩国产高清视频在线| 亚洲欧美激情视频| 日产精品久久久一区二区福利| 成人国产精品久久久久久亚洲| 色七七影院综合| 久久综合免费视频| 国产精品久久电影观看| 成人有码视频在线播放| 日韩av中文字幕在线免费观看| 日韩av在线资源| 欧美中文字幕精品| 久久精品中文字幕电影| www国产亚洲精品久久网站| 精品美女国产在线| 青青草原一区二区| 92看片淫黄大片看国产片| 97在线视频免费播放| 中文字幕视频在线免费欧美日韩综合在线看| 91中文在线视频| 日韩精品视频免费在线观看| 欧美激情精品久久久久久黑人| 亚洲精品国产精品国自产在线| 国产视频在线一区二区| 国产精品久久久久久久久久久久久| 深夜福利国产精品| 欧美综合在线观看| 欧美在线www| 综合136福利视频在线| 亚洲国产精品资源| 欧美日韩精品在线| 成人在线视频福利| 亚洲福利在线播放| 456亚洲影院| 国产精品jvid在线观看蜜臀| 美女福利精品视频| 亚洲精品国产精品乱码不99按摩| 欧美最猛性xxxxx(亚洲精品)| 91最新国产视频| 久久久久久久久久婷婷| 欧美网站在线观看| 中国china体内裑精亚洲片| 亚洲一区美女视频在线观看免费| 色综合五月天导航| 国产中文日韩欧美| 国产日韩欧美电影在线观看| 国产精品久久久久久久久久尿| 日韩av一卡二卡| 日韩欧中文字幕| 国产成人亚洲综合青青| 美女久久久久久久| 久久亚洲一区二区三区四区五区高| 欧美一级bbbbb性bbbb喷潮片| 亚洲另类xxxx| 久久成年人免费电影| 亚洲aⅴ男人的天堂在线观看| www.美女亚洲精品| 国产亚洲视频中文字幕视频| 91香蕉电影院| 欧美人与性动交a欧美精品| 久久久精品一区| 欧美老肥婆性猛交视频| 另类少妇人与禽zozz0性伦| 一区二区三区四区视频| 日韩成人小视频| 日韩精品在线观看一区二区| 亚洲成人精品久久| 成人黄色大片在线免费观看| 少妇高潮久久77777| 国产午夜精品美女视频明星a级| 影音先锋日韩有码| 亚洲国产欧美一区| 在线视频中文亚洲| 欧美日韩免费观看中文| 色综合伊人色综合网站| 亚洲aa在线观看| 日本sm极度另类视频| 国产欧美一区二区三区在线| 国产97在线|日韩| 亚洲第一页在线| 国产精品视频在线播放| 91亚洲国产精品| 国产成人激情小视频| 亚洲欧美中文日韩v在线观看| 久久免费高清视频| 欧美电影免费观看高清完整| 性欧美视频videos6一9| 亚洲天堂免费观看| 久久久久久久久国产| 国产69精品久久久久9| 在线播放日韩专区| 国产亚洲欧洲高清| 国内精品久久久久影院 日本资源| 亚洲最大的免费| 久久成人av网站| 精品视频在线播放免| 欧美激情2020午夜免费观看| 国产精品88a∨| 国产精品精品国产| 日韩精品中文字幕有码专区| 在线性视频日韩欧美| 欧美—级高清免费播放| 国产精品人人做人人爽| 成人精品久久一区二区三区| 91麻豆国产精品| 国产亚洲一级高清| 亚洲欧美日本精品| 亚洲性夜色噜噜噜7777| 久久精品夜夜夜夜夜久久| 欧美激情a在线| 国产精品wwww|