如何在 Flask 上返回 400(错误请求)?

Posted

技术标签:

【中文标题】如何在 Flask 上返回 400(错误请求)?【英文标题】:How to return 400 (Bad Request) on Flask? 【发布时间】:2019-12-31 01:31:33 【问题描述】:

我创建了一个简单的烧瓶应用程序,我正在读取来自 python 的响应:

response = requests.post(url,data=json.dumps(data), headers=headers ) 
data = json.loads(response.text)

现在我的问题是在某些情况下我想返回 400 或 500 消息响应。到目前为止,我正在这样做:

abort(400, 'Record not found') 
#or 
abort(500, 'Some error...') 

这确实会在终端上打印消息:

但在 API 响应中,我不断收到 500 错误响应:

代码结构如下:

|--my_app
   |--server.py
   |--main.py
   |--swagger.yml

server.py 有这个代码:

from flask import render_template
import connexion
# Create the application instance
app = connexion.App(__name__, specification_dir="./")
# read the swagger.yml file to configure the endpoints
app.add_api("swagger.yml")
# Create a URL route in our application for "/"
@app.route("/")
def home():
    """
    This function just responds to the browser URL
    localhost:5000/

    :return:        the rendered template "home.html"
    """
    return render_template("home.html")
if __name__ == "__main__":
    app.run(host="0.0.0.0", port="33")

main.py 拥有我用于 API 端点的所有功能。

例如:

def my_funct():
   abort(400, 'Record not found') 

my_funct 被调用时,我在终端上打印了Record not found,但在API 本身的响应中却没有,我总是收到500 消息错误。

【问题讨论】:

显示路线的完整代码——你目前分享的很少,我不知道你是不是return正在中止,还是你有其他逻辑错误。 对于它的价值,404 是“找不到记录”的规范代码。见List of HTTP status codes @Doobeh 我刚刚更新了问题 【参考方案1】:

您有多种选择:

最基本的:

@app.route('/')
def index():
    return "Record not found", 400

如果要访问标头,可以抓取响应对象:

@app.route('/')
def index():
    resp = make_response("Record not found", 400)
    resp.headers['X-Something'] = 'A value'
    return resp

或者你可以让它更明确,不仅仅是返回一个数字,而是返回一个状态码对象

from flask_api import status

@app.route('/')
def index():
    return "Record not found", status.HTTP_400_BAD_REQUEST

延伸阅读:

您可以在此处阅读有关前两个的更多信息:About Responses(Flask 快速入门) 第三个在这里:Status codes(Flask API 指南)

【讨论】:

【参考方案2】:

我喜欢使用flask.Response 类:

from flask import Response


@app.route("/")
def index():
    return Response(
        "The response body goes here",
        status=400,
    )

flask.abortwerkzeug.exceptions.abort 的一个包装器,它实际上只是一个helper method,以便更容易引发 HTTP 异常。在大多数情况下这很好,但对于 RESTful API,我认为明确返回响应可能会更好。

【讨论】:

谁能详细说明 Response 类在仅返回 str/code 元组时添加了什么? @AdamHughes 在这种情况下它们是相同的,因为 Flask 在您传递元组时调用 Response 。 Response 还允许您设置内容类型和 mime 类型,但我相信您可以在不导入响应的情况下执行此操作。 Miguel Grinberg 有 this 发言。【参考方案3】:

这是我多年前编写的 Flask 应用程序中的一些 sn-ps。它有一个 400 响应的示例

import werkzeug
from flask import Flask, Response, json
from flask_restplus import reqparse, Api, Resource, abort
from flask_restful import request
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

api = Api(app)

parser = reqparse.RequestParser()
parser.add_argument('address_to_score', type=werkzeug.datastructures.FileStorage, location='files')

class MissingColumnException(Exception):
    pass

class InvalidDateFormatException(Exception):
    pass

@api.route('/project')
class Project(Resource):

    @api.expect(parser)
    @api.response(200, 'Success')
    @api.response(400, 'Validation Error')
    def post(self):
        """
        Takes in an excel file of addresses and outputs a JSON with scores and rankings.
        """
        try:
            df, input_trees, needed_zones = data.parse_incoming_file(request)

        except MissingColumnException as e:
            abort(400, 'Excel File Missing Mandatory Column(s):', columns=str(e))

        except Exception as e:
            abort(400, str(e))

        project_trees = data.load_needed_trees(needed_zones, settings['directories']['current_tree_folder'])

        df = data.multiprocess_query(df, input_trees, project_trees)
        df = data.score_locations(df)
        df = data.rank_locations(df)
        df = data.replace_null(df)
        output_file = df.to_dict('index')
        resp = Response(json.dumps(output_file), mimetype='application/json')
        resp.status_code = 200

    return resp

@api.route('/project/health')
class ProjectHealth(Resource):

    @api.response(200, 'Success')
    def get(self):
        """
        Returns the status of the server if it's still running.
        """
        resp = Response(json.dumps('OK'), mimetype='application/json')
        resp.status_code = 200

    return resp

【讨论】:

【参考方案4】:

您可以返回一个元组,其中第二个元素是状态(400 或 500)。

from flask import Flask
app = Flask(__name__)


@app.route('/')
def hello():
    return "Record not found", 400

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

python调用API示例:

import requests

response = requests.get('http://127.0.0.1:5000/')

response.text
# 'This is a bad request!'

response.status_code
# 400

【讨论】:

【参考方案5】:

我认为您正确使用了abort() 函数。我怀疑这里的问题是错误处理程序是捕获 400 错误然后出错导致 500 错误。有关烧瓶错误处理的更多信息,请参阅here。

例如,以下内容会将 400 更改为 500 错误:

@app.errorhandler(400)
def handle_400_error(e):
    raise Exception("Unhandled Exception")

如果你没有做任何错误处理,它可能来自connexion 框架,虽然我不熟悉这个框架。

【讨论】:

以上是关于如何在 Flask 上返回 400(错误请求)?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不导致400错误请求错误的情况下使用Python Flask“打开”复选框?

通过表单在 Flask 上发布数据给出 400 Bad Request

[使用Flask和Google Cloud Storage进行400错误的错误请求

烧瓶根据邮递员的邮寄请求返回 400

如何修复:远程服务器返回错误:(400)错误请求

如何创建 400 错误请求以便我可以验证功能