Bagaimana cara mendapatkan JSON POST dalam Flask?

326

Saya mencoba membangun API sederhana menggunakan Flask, di mana saya sekarang ingin membaca beberapa JSON POST. Saya melakukan POST dengan ekstensi Chrome tukang pos, dan JSON I POST sederhana {"text":"lalala"}. Saya mencoba membaca JSON menggunakan metode berikut:

@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
    content = request.json
    print content
    return uuid

Di browser, ia mengembalikan UUID yang saya masukkan ke GET dengan benar, tetapi di konsol, ia hanya mencetak None(di mana saya mengharapkannya untuk mencetak {"text":"lalala"}. Apakah ada yang tahu bagaimana saya bisa mendapatkan JSON yang diposting dari dalam metode Flask?

kramer65
sumber

Jawaban:

428

Pertama-tama, .jsonatribut adalah properti yang mendelegasikan request.get_json()metode , yang mendokumentasikan mengapa Anda melihatnyaNone sini.

Anda perlu mengatur tipe konten permintaan application/jsonagar .jsonproperti dan .get_json()metode (tanpa argumen) berfungsi karena keduanya akan menghasilkan Nonesebaliknya. Lihat dokumentasi FlaskRequest :

Ini akan berisi data JSON yang diuraikan jika mimetype menunjukkan JSON ( application / json , lihat is_json()), jika tidak maka akan menjadi None.

Anda dapat meminta request.get_json()untuk melewati persyaratan jenis konten dengan mengirimkannyaforce=True argumen kata kunci.

Perhatikan bahwa jika pengecualian muncul pada titik ini (mungkin menghasilkan respons 400 Permintaan Buruk), data JSON Anda tidak valid. Dalam beberapa hal cacat; Anda mungkin ingin memeriksanya dengan validator JSON.

Martijn Pieters
sumber
Saya pikir ketika pengecualian dinaikkan pada titik ini seharusnya lebih cenderung menghasilkan respons 500 Kesalahan Internal, bukan?
iBug
101

Untuk referensi, inilah kode lengkap bagaimana mengirim json dari klien Python:

import requests
res = requests.post('http://localhost:5000/api/add_message/1234', json={"mytext":"lalala"})
if res.ok:
    print res.json()

Input "json =" akan secara otomatis mengatur tipe konten, seperti yang dibahas di sini: Posting JSON menggunakan Permintaan Python

Dan klien di atas akan bekerja dengan kode sisi server ini:

from flask import Flask, request, jsonify
app = Flask(__name__)

@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
    content = request.json
    print content['mytext']
    return jsonify({"uuid":uuid})

if __name__ == '__main__':
    app.run(host= '0.0.0.0',debug=True)
Luke
sumber
71

Ini adalah cara saya akan melakukannya dan memang seharusnya begitu

@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
    content = request.get_json(silent=True)
    # print(content) # Do your processing
    return uuid

Dengan silent=Trueset, get_jsonfungsi akan gagal secara diam-diam ketika mencoba mengambil tubuh json. Secara default ini diatur ke False. Jika Anda selalu mengharapkan json body (tidak opsional), biarkan saja silent=False.

Pengaturan force=Trueakan mengabaikan request.headers.get('Content-Type') == 'application/json'pemeriksaan yang dilakukan flask untuk Anda. Secara default ini juga diatur ke False.

Lihat dokumentasi labu .

Saya akan sangat menyarankan untuk pergi force=Falsedan membuat klien mengirim Content-Typetajuk untuk membuatnya lebih eksplisit.

Semoga ini membantu!

radtek
sumber
2
Tergantung apakah json body adalah opsional atau tidak, jadi tergantung pada kasus Anda
radtek
2
Saya tidak dapat melihat kasus di mana masuk akal untuk beberapa kali mengirim json yang valid dan lain kali json tidak valid. Kedengarannya seperti dua titik akhir yang berbeda
vidstige
1
Seperti saya katakan, jika titik akhir mengambil tubuh json "opsional", Anda dapat menggunakan silent=True. Ya ini mungkin, dan saya menggunakannya. Ini benar-benar didasarkan pada bagaimana Anda merancang API Anda untuk dikonsumsi. Jika tidak ada kasus seperti itu untuk titik akhir Anda, cukup hapus silent=Trueatau atur secara eksplisit False.
radtek
Untuk kejelasan, print(content)setelah content = request.get_json()mencetak objek ... tetapi sebagai objek Python yang valid (dan bukan sebagai objek JSON yang valid). Sebagai contoh, ia menggunakan tanda kutip tunggal sementara JSON secara ketat membutuhkan tanda kutip ganda untuk kedua nilai kunci (string) sebagai nilai string. Jika Anda ingin representasi JSON, gunakan json.dumps()dengan objek.
Jochem Schulenklopper
24

Dengan asumsi Anda telah memposting JSON yang valid dengan application/jsonjenis konten, request.jsonakan memiliki data JSON yang diuraikan.

from flask import Flask, request, jsonify

app = Flask(__name__)


@app.route('/echo', methods=['POST'])
def hello():
   return jsonify(request.json)
trojek
sumber
3
Untuk menambah jawaban ini, permintaan yang bisa Anda kirim ke titik akhir ini bisa response = request.post('http://127.0.0.1:5000/hello', json={"foo": "bar"}). Setelah menjalankan ini response.json()harus kembali{'foo': 'bar'}
ScottMcC
Dapat dicatat bahwa {'foo': 'bar'}JSON tidak valid. Ini bisa menjadi representasi objek Python yang valid yang sangat mirip JSON, tetapi JSON yang valid secara ketat menggunakan tanda kutip ganda.
Jochem Schulenklopper
@JochemSchulenklopper get_json()metode permintaan menerjemahkan dari JSON ke objek Python, ya. Di mana Anda mengharapkannya untuk menghasilkan dokumen JSON yang valid?
Martijn Pieters
@ MartijnPieters, saya baru saja membuat pernyataan tentang kekhasan yang menggigit saya setidaknya dua kali :-) Tapi ya, biasanya saya mengharapkan fungsi yang dipanggil .json()atau .get_json()mengembalikan representasi objek JSON yang valid, bukan dict Python. Saya hanya melihat nama, dan menyimpulkan apa yang keluar dari itu.
Jochem Schulenklopper
6

Untuk semua orang yang masalahnya berasal dari panggilan ajax, berikut adalah contoh lengkapnya:

Panggilan Ajax: kuncinya di sini adalah menggunakan a dictlaluJSON.stringify

    var dict = {username : "username" , password:"password"};

    $.ajax({
        type: "POST", 
        url: "http://127.0.0.1:5000/", //localhost Flask
        data : JSON.stringify(dict),
        contentType: "application/json",
    });

Dan di sisi server:

from flask import Flask
from flask import request
import json

app = Flask(__name__)

@app.route("/",  methods = ['POST'])
def hello():
    print(request.get_json())
    return json.dumps({'success':True}), 200, {'ContentType':'application/json'} 

if __name__ == "__main__":
    app.run()
Arcyno
sumber
1
Ini adalah hal yang bekerja untuk saya, terima kasih banyak! :)
vjjj
1

Untuk memberikan pendekatan lain.

from flask import Flask, jsonify, request
app = Flask(__name__)

@app.route('/service', methods=['POST'])
def service():
    data = json.loads(request.data)
    text = data.get("text",None)
    if text is None:
        return jsonify({"message":"text not found"})
    else:
        return jsonify(data)

if __name__ == '__main__':
    app.run(host= '0.0.0.0',debug=True)
Ömer Taban
sumber
0

Dengan asumsi bahwa Anda telah memposting JSON yang valid,

@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
    content = request.json
    print content['uuid']
    # Return data as JSON
    return jsonify(content)
RAJAHMAD MULANI
sumber
0

Coba gunakan parameter kekuatan ...

request.get_json(force = True)

Menukik
sumber