【问题标题】:How to get POSTed JSON in Flask?如何在 Flask 中获取 POSTed JSON?
【发布时间】:2013-11-28 20:31:16
【问题描述】:

我正在尝试使用 Flask 构建一个简单的 API,现在我想在其中读取一些 POSTed JSON。我使用 Postman Chrome 扩展程序进行 POST,而我 POST 的 JSON 只是 {"text":"lalala"}。我尝试使用以下方法读取 JSON:

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

在浏览器上,它正确返回了我在 GET 中输入的 UUID,但在控制台上,它只打印出 None(我希望它打印出 {"text":"lalala"}。有人知道我如何获得从 Flask 方法中发布 JSON?

【问题讨论】:

    标签: python json post flask


    【解决方案1】:

    首先,.json 属性是一个委托给request.get_json() method 的属性,它记录了您在此处看到None 的原因。

    您需要将请求内容类型设置为application/json 以使.json 属性和.get_json() 方法(不带参数)正常工作,否则将产生None。见Flask Request documentation

    如果 mimetype 指示 JSON(application/json,请参阅is_json()),这将包含解析的 JSON 数据,否则它将是 None

    您可以通过将 force=True 关键字参数传递给 request.get_json() 来告诉 request.get_json() 跳过内容类型要求。

    请注意,如果此时引发异常(可能导致 400 错误请求响应),则您的 JSON 数据 无效。它在某种程度上是畸形的;您可能需要使用 JSON 验证器对其进行检查。

    【讨论】:

    • 我认为此时引发 异常 时,它应该更有可能导致 500 内部错误响应,不是吗?
    • @iBug 这是一个老问题,但答案应该是 400,因为如果请求没有格式错误,就不会引发异常。
    • @iBug:请求中格式错误的 JSON 不是服务器错误,而是客户端的错误,使其成为 400 类错误。
    【解决方案2】:

    作为参考,这里是如何从 Python 客户端发送 json 的完整代码:

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

    “json=”输入将自动设置内容类型,如下所述:How to POST JSON data with Python Requests?

    上面的客户端将使用这个服务器端代码:

    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)
    

    【讨论】:

      【解决方案3】:

      这是我会做的,应该是这样的

      @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

      flask documentation

      我强烈建议离开force=False 并让客户端发送Content-Type 标头以使其更明确。

      希望这会有所帮助!

      【讨论】:

      • 我看不到任何情况下有时发布有效的 json 和其他时间无效的 json 是有意义的。听起来像是两个不同的终点
      • 就像我说的,如果端点采用“可选”json 正文,您可以使用silent=True。是的,这是可能的,我确实使用它。它实际上基于您设计要使用的 API 的方式。如果您的端点没有这种情况,只需删除 silent=True 或将其显式设置为 False
      【解决方案4】:

      假设您已发布具有 application/json 内容类型的有效 JSON,request.json 将拥有解析后的 JSON 数据。

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

      【讨论】:

      • 要添加到此答案,您可以发送到此端点的请求可以是response = request.post('http://127.0.0.1:5000/hello', json={"foo": "bar"})。在此运行之后 response.json() 应该返回 {'foo': 'bar'}
      【解决方案5】:

      对于所有问题来自 ajax 调用的人,这里有一个完整的示例:

      Ajax 调用:这里的关键是使用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()
      

      【讨论】:

      • 注意,由于某种原因,如果 dict 被定义为 const,例如 const foo = {hello: "world"},它将无法工作。
      【解决方案6】:

      您可能会注意到request.jsonrequest.get_json() 仅在Content-type: application/json 已添加到请求的标头中时才有效。如果您无法更改客户端请求配置,则可以像这样获取正文为 json:

      data = json.loads(request.data)
      

      【讨论】:

      • 这对我有用,当请求以 JSON 格式作为正文发送时,尝试为 dialogflow webhook 编写谷歌云函数
      【解决方案7】:

      给出另一种方法。

      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)
      

      【讨论】:

      • 对我来说最好的答案...工作正常,谢谢
      【解决方案8】:

      尝试使用 force 参数...

      request.get_json(force = True)

      【讨论】:

        【解决方案9】:

        假设您发布了有效的 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)
        

        【讨论】:

          【解决方案10】:

          可以使用以下代码:

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

          这是我获取json数据的截图:

          可以看到返回的是字典类型的数据。

          【讨论】:

            【解决方案11】:

            尝试在get_json()方法中设置force属性为True来解决这个问题。

            request.get_json(force = True)
            

            【讨论】:

              【解决方案12】:

              尽管我在这里遇到的所有答案都是正确的。有些事情我认为应该作为更好的做法来做。以下是我的写法。

              from flask import app, request, Flask, jsonify
              
              
              @app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
              def add_message(uuid):
                  
                  # Check if the request method is POST
                  if request.method == 'POST':
                      # content will return eather parse data as JSON
                      # Or None incase there is no data
                      content = request.get_json()
                      print(content)
                      # The content could be displayed in html page if serialized as json
                      return jsonify(content) # Return null if there is content
              
                  # if it is only get request then just return uuid
                  return uuid
              

              【讨论】:

                猜你喜欢
                • 2015-10-05
                • 1970-01-01
                • 2017-08-30
                • 2015-10-05
                相关资源
                最近更新 更多