确保POST数据是有效的JSON格式。

6

我正在使用Python Flask开发一个JSON API。

我的目标是始终返回JSON,并指示任何出现的错误消息。

该API也只接受POST请求体中的JSON数据,但如果Flask无法将数据读取为JSON,则默认返回HTML错误400。

最好不强制用户发送 Content-Type 标头,如果是 raw 或者 text 内容类型,仍然尝试解析主体为JSON。

简而言之,我需要一种验证POST请求体是否为JSON的方法,并自行处理错误。

我已经阅读了有关在request中添加装饰器来完成此操作的内容,但没有全面的示例。


你可以按照这里所说的,使用force=True来请求request中的get_json方法 https://flask.readthedocs.io/en/latest/api/#flask.Request.get_json。如果它返回None,也就是request.get_json()不存在,那么你可以抛出一个错误或者让它引发一个400错误。 - lapinkoira
@lapinkoira:当调用该方法时,如果不设置 silent=True,它会引发一个 BadRequest 异常。 - Martijn Pieters
如果OP说没有内容类型应用程序JSON,那么默认情况下,如果MIME类型不是application/json,则此函数将返回None。 - lapinkoira
@lapinkoira @Martijn Pieters:将force=Truesilent=True组合使用确实会使request.get_json在错误或无数据时返回None,这正是我需要的答案。我会查看@Martijn Pieters的解决方案,但现在我已经有了一个可行的解决方案。 - DrakaSAN
3个回答

9

您有三个选项:

就我个人而言,我可能会选择第二个选项:

from werkzeug.exceptions import BadRequest
from flask import json, Request, _request_ctx_stack


class JSONBadRequest(BadRequest):
    def get_body(self, environ=None):
        """Get the JSON body."""
        return json.dumps({
            'code':         self.code,
            'name':         self.name,
            'description':  self.description,
        })

    def get_headers(self, environ=None):
        """Get a list of headers."""
        return [('Content-Type', 'application/json')]


def on_json_loading_failed(self):
    ctx = _request_ctx_stack.top
    if ctx is not None and ctx.app.config.get('DEBUG', False):
        raise JSONBadRequest('Failed to decode JSON object: {0}'.format(e))
    raise JSONBadRequest()


Request.on_json_loading_failed = on_json_loading_failed

现在,每当request.get_json()失败时,它将调用您的自定义on_json_loading_failed方法,并引发一个带有JSON负载而不是HTML负载的异常。

1

如果将选项force=Truesilent=True结合起来,当数据无法解析时,request.get_json的结果将为None,然后使用简单的if语句可以检查解析情况。

from flask import Flask
from flask import request

@app.route('/foo', methods=['POST'])
def function(function = None):
    print "Data: ", request.get_json(force = True, silent = True);
    if request.get_json() is not None:
        return "Is JSON";
    else:
        return "Nope";

if __name__ == "__main__":
    app.run()

感谢lapinkoira和Martijn Pieters。


0
你可以尝试使用Python的JSON库来解码JSON对象。 主要思路是获取纯文本请求体并尝试转换为JSON格式。例如:
import json
...
# somewhere in view
def view():
    try:
        json.loads(request.get_data())
    except ValueError:
        # not a JSON! return error
        return {'error': '...'}
    # do plain stuff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接