flask中使用jsonify和json.dumps的區別

pythontab發表於2018-03-26

flask提供了jsonify函式供使用者處理返回的序列化json資料,而python自帶的json庫中也有dumps方法可以序列化json物件,那麼在flask的檢視函式中return它們會有什麼不同之處呢?

想必開始很多人和我一樣搞不清楚,只知道既然框架提供了方法就用,肯定不會錯。

但作為開發人員,我們需要弄清楚開發過程中各種實現方式的特點和區別,這樣在我們面對不同的需求時才能做出相對合理的選擇,而不是千篇一律地使用自己熟悉的。下面我就jsonify和json.dumps的區別這一問題簡單探討一下。


一、實驗

python的flask框架為使用者提供了直接返回包含json格式資料響應的方法,即jsonify,在開發中會經常用到。如下一段簡單的flask後端程式碼,服務端檢視函式根據請求引數返回json格式的資料到客戶端。

from flask import Flask
from flask import jsonify
from flask import Response
app = Flask(__name__)
@app.route('/hello/<name>/<words>',methods=['GET'])
def hello(name,words):
  return jsonify({'name':name,'words':words})#也可以傳入key=value形式的引數,如jsonify(name=name,words=words)
if __name__ == '__main__':
  app.run()

用chrome瀏覽器訪問頁面, 可以開啟控制檯看到Content-Type: application/json



現在我們改為使用python自帶的json庫json.dumps作為檢視函式的直接返回值,程式碼如下:

from flask import Flask
from flask import jsonify
from flask import Response
app = Flask(__name__)
@app.route('/hello/<name>/<words>',methods=['GET'])
def hello(name,words):
  return json.dumps({'name':name,'words':words})
if __name__ == '__main__':
  app.run()

PS: 直接返回json.dumps的結果是可行的,因為flask會判斷並使用make_response方法自動構造出響應,只不過響應頭各個欄位是預設的。若要自定義響應欄位,則可以使用make_response或Response自行構造響應。

用chrome瀏覽器訪問頁面, 可以開啟控制檯看到Content-Type: text/html;charset=utf-8


二、分析

1.Content-Type有區別

jsonify的作用實際上就是將我們傳入的json形式資料序列化成為json字串,作為響應的body,並且設定響應的Content-Type為application/json,構造出響應返回至客戶端。jsonify的部分原始碼如下:

def jsonify(*args, **kwargs):
  if __debug__:
    _assert_have_json()
    return current_app.response_class(json.dumps(dict(*args, **kwargs),indent=None if request.is_xhr else 2), mimetype='application/json')

可以看出jsonify實際上也是使用了json.dumps來序列化json形式的資料,作為響應正文返回。indent表示json格式化的縮排,若是Ajax請求則不縮排(因為一般Ajax資料沒必要直接展示),否則縮排2格。但想必從第一部分的實驗結果我們已經看出來了,使用jsonify時響應的Content-Type欄位值為application/json,而使用json.dumps時該欄位值為text/html。Content-Type決定了接收資料的一方如何看待資料,如何處理資料,如果是application/json,則可以直接當做json物件處理,若是text/html,則還要將文字物件轉化為json物件再做處理(個人理解,有誤請指正)。


2.接受引數有區別

jsonify可以接受和python中的dict構造器同樣的引數,而json.dumps比jsonify可以多接受list型別和一些其他型別的引數。但我試了一下,形式為key1=value1,[key2=value2,...]這樣的引數是不行的,會報出“TypeError: dumps() takes exactly 1 argument (0 given)”這一錯誤,而jsonify不會報錯並能正常返回資料。


最後,我們可以使用flask中的make_response方法或者直接透過Response類,透過設定mimetype引數來達到和使用jsonify差不多的效果,但少寫點程式碼何樂而不為呢?況且簡潔一點更不容易出錯,引數越多除錯和維護就越麻煩。當然,使用哪個並不是絕對的,必要時要根據前端的資料處理方式來決定。


相關文章