Як отримати POSTed JSON у колбі?


326

Я намагаюся створити простий API за допомогою Flask, в якому зараз я хочу прочитати деякі POSTed JSON. Я виконую пошту з розширенням Postman Chrome, а JSON I POST - просто {"text":"lalala"}. Я намагаюся прочитати JSON за допомогою наступного методу:

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

У браузері він правильно повертає UUID, який я помістив у GET, але на консолі він просто роздруковує None(де я очікую, що він роздрукує {"text":"lalala"}. Хто-небудь знає, як я можу отримати опублікований JSON у рамках методу Flask?

Відповіді:


427

Перш за все, .jsonатрибут - це властивість, яка делегує request.get_json()метод , який документує, чому ви бачите Noneтут.

Потрібно встановити тип вмісту запиту на те, application/jsonщоб .jsonвластивість та .get_json()спосіб (без аргументів) працювали, оскільки будь-який буде створювати Noneінше. Дивіться документацію на колбуRequest :

Це буде містити проаналізовані дані JSON, якщо в mimetype вказується JSON ( application / json , див. is_json()), Інакше це буде None.

Ви можете сказати request.get_json()пропустити вимогу щодо типу вмісту, передавши йому force=Trueаргумент ключового слова.

Зауважте, що якщо в цей момент буде винято виняток (можливо, це призведе до відповіді на 400 запитів), ваші дані JSON недійсні. Він певним чином деформований; Ви можете перевірити це за допомогою валідатора JSON.


Я подумав, що, коли в цьому моменті буде зроблено виняток, це швидше має призвести до відповіді 500 внутрішніх помилок, чи не так?
iBug

100

Для довідки, ось повний код, як надіслати json з клієнта Python:

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

Вхід "json =" автоматично встановить тип вмісту, як обговорювалося тут: Опублікувати JSON за допомогою запитів Python

І вищезазначений клієнт буде працювати з цим кодом на стороні сервера:

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)

71

Це так, як я це зробив би і повинен бути

@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

Якщо silent=Trueвстановити, get_jsonфункція буде виходити з ладу при спробі отримати тіло json. За замовчуванням для цього встановлено значення False. Якщо ви завжди очікуєте тіло json (необов'язково), залиште його як silent=False.

Налаштування force=Trueігнорує request.headers.get('Content-Type') == 'application/json'чек, який робить колба для вас. За замовчуванням це також встановлено False.

Дивіться документацію на колбу .

Я настійно рекомендую залишити force=Falseі змусити клієнта надіслати Content-Typeзаголовок, щоб зробити його більш чітким.

Сподіваюсь, це допомагає!


2
Залежить, чи тіло json необов’язкове чи ні, тому залежить від вашого випадку
radtek

2
Я не бачу жодного випадку, коли було б сенс розміщувати дійсний json та інший раз недійсний json. Звучить як дві різні кінцеві точки
vidstige

1
Як я вже сказав, якщо кінцева точка приймає "необов'язкове" тіло json, ви можете використовувати silent=True. Так, це можливо, і я цим користуюся. Дійсно базується на тому, як ви розробляєте свій API для споживання. Якщо для вашої кінцевої точки немає подібного випадку, просто видаліть silent=Trueабо явно встановіть його False.
radtek

Для наочності print(content)після цього content = request.get_json()друкується об’єкт ..., але як дійсний об'єкт Python (а не як дійсний об'єкт JSON). Наприклад, він використовує одинарні лапки, тоді як JSON суворо вимагає подвійних лапок для обох ключових значень (рядків) як рядкових значень. Якщо ви хочете представити JSON, використовуйте json.dumps()об'єкт.
Йохем Шуленклоппер

24

Якщо припустити, що ви розмістили дійсний JSON з application/jsonтипом вмісту, request.jsonбуде проаналізовано дані JSON.

from flask import Flask, request, jsonify

app = Flask(__name__)


@app.route('/echo', methods=['POST'])
def hello():
   return jsonify(request.json)

3
Щоб додати до цієї відповіді, може бути запит, який ви могли б надіслати до цієї кінцевої точки response = request.post('http://127.0.0.1:5000/hello', json={"foo": "bar"}). Після цього біг response.json()повинен повернутися{'foo': 'bar'}
ScottMcC

Можна зазначити, що {'foo': 'bar'}JSON не є дійсним. Це може бути дійсне представлення об’єкта Python, яке дуже схоже на JSON, але дійсне JSON суворо використовує подвійні лапки.
Йохем Шуленклоппер

@JochemSchulenklopper get_json()метод запиту декодує від JSON до об'єктів Python, так. Де ви очікуєте, що він створить дійсний документ JSON?
Martijn Pieters

@MartijnPieters, я щойно робив заяву про особливість, яка мене прикусила щонайменше двічі :-) Але так, як правило, я очікую виклику функції .json()або .get_json()повернення дійсного JSON-об’єкта, а не диктату Python. Я просто дивлюсь на ім’я та роблю висновок про те, що може вийти з нього.
Йохім Шуленклоппер

5

Для всіх тих, чий випуск був із дзвінка Ajax, ось повний приклад:

Ajax call: ключовим тут є використання a dictі тодіJSON.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",
    });

І на стороні сервера:

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()

1
Це те, що працювало для мене, велике спасибі! :)
vjjj

1

Дати інший підхід.

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)

0

Якщо припустити, що ви опублікували дійсний JSON,

@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)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.