如何在 Flask 中处理传入的请求数据

介绍

Web 应用程序经常需要处理来自用户的传入请求数据。此有效负载可以采用查询字符串、表单数据和 JSON 对象的形式。Flask与任何其他 Web 框架一样,允许您访问请求数据。

在本教程中,您将使用三个接受查询字符串、表单数据或 JSON 对象的路由构建一个 Flask 应用程序。

先决条件

要完成本教程,您需要:

  • 该项目需要在本地环境中安装 Python
  • 该项目将使用Pipenv,这是一个生产就绪的工具,旨在将所有打包世界中最好的东西带到 Python 世界。它将 Pipfile、pip 和virtualenv整合到一个命令中。
  • 测试 API 端点需要下载并安装Postman 之类的工具

本教程已通过 Pipenv v2020.11.15、Python v3.9.0 和 Flask v1.1.2 验证。

设置项目

为了演示使用请求的不同方式,您需要创建一个 Flask 应用程序。尽管示例应用程序对视图函数和路由使用了简化的结构,但您在本教程中学到的知识可以应用于任何组织视图的方法,例如基于类的视图、蓝图或 Flask-Via 等扩展。

首先,您需要创建一个项目目录。打开终端并运行以下命令:

  • mkdir flask_request_example

然后,导航到新目录:

  • cd flask_request_example

接下来,安装烧瓶。打开终端并运行以下命令:

  • pipenv install Flask

pipenv命令将为该项目创建一个 virtualenv、一个 Pipfile、installflask和一个 Pipfile.lock。

要激活项目的 virtualenv,请运行以下命令:

  • pipenv shell

要访问 Flask 中的传入数据,您必须使用该request对象。request对象保存来自请求的所有传入数据,其中包括 mimetype、引用者、IP 地址、原始数据、HTTP 方法和标头等。

尽管request对象保存的所有信息都有用,但就本文而言,您将重点关注通常由端点调用方直接提供的数据。

要访问 Flask 中的请求对象,您需要从 Flask 库中导入它:

from flask import request

然后您就可以在任何视图函数中使用它。

使用您的代码编辑器创建一个app.py文件。导入Flaskrequest对象。并为query-exampleform-example、 和建立路由json-example

应用程序
# import main Flask class and request object
from flask import Flask, request

# create the Flask app
app = Flask(__name__)

@app.route('/query-example')
def query_example():
    return 'Query String Example'

@app.route('/form-example')
def form_example():
    return 'Form Data Example'

@app.route('/json-example')
def json_example():
    return 'JSON Object Example'

if __name__ == '__main__':
    # run app in debug mode on port 5000
    app.run(debug=True, port=5000)

接下来,打开终端并使用以下命令启动应用程序:

  • python app.py

该应用程序将在端口 5000 上启动,因此您可以使用以下链接在浏览器中查看每条路线:

http://127.0.0.1:5000/query-example (or localhost:5000/query-example)
http://127.0.0.1:5000/form-example (or localhost:5000/form-example)
http://127.0.0.1:5000/json-example (or localhost:5000/json-example)

的代码建立三条路线和访问每个路由将要显示的消息"Query String Example""Form Data Example""JSON Object Example"分别。

使用查询参数

添加到查询字符串的 URL 参数是将数据传递到 Web 应用程序的常用方法。在浏览网页时,您之前可能遇到过查询字符串。

查询字符串类似于以下内容:

example.com?arg1=value1&arg2=value2

查询字符串在问号 ( ?) 字符之后开始

example.com?arg1=value1&arg2=value2

并且具有由与号 ( &) 字符分隔的键值对

example.com?arg1=value1&arg2=value2

对于每一对,键后跟一个等号 ( =) 字符,然后是值。

arg1 : value1
arg2 : value2

查询字符串对于传递不需要用户采取行动的数据很有用。您可以在应用程序的某处生成一个查询字符串并将其附加到一个 URL 中,这样当用户发出请求时,数据会自动传递给他们。查询字符串也可以由具有 GET 作为方法的表单生成。

让我们向query-example路由添加一个查询字符串在这个假设示例中,您将提供将显示在屏幕上的编程语言的名称。创建一个键"language"和一个值"Python"

http://127.0.0.1:5000/query-example?language=Python

如果您运行该应用程序并导航到该 URL,您将看到它仍然显示"Query String Example".

您需要对处理查询参数的部分进行编程。此代码将language使用request.args.get('language')读入密钥request.args['language']

通过调用request.args.get('language'),如果languageURL 中不存在密钥,应用程序将继续运行在这种情况下,该方法的结果将为None

通过调用request.args['language'],如果languageURL 中不存在密钥,应用程序将返回 400 错误

处理查询字符串时,建议使用request.args.get(),防止app失败。

让我们读取language密钥并将其显示为输出。

使用以下代码修改query-example路由app.py

应用程序
@app.route('/query-example')
def query_example():
    # if key doesn't exist, returns None
    language = request.args.get('language')

    return '''<h1>The language value is: {}</h1>'''.format(language)

然后,运行应用程序并导航到 URL:

http://127.0.0.1:5000/query-example?language=Python

浏览器应显示以下消息:

Output
The language value is: Python

URL 中的参数被分配给language变量,然后返回给浏览器。

要添加更多查询字符串参数,您可以在 URL 末尾附加与号和新的键值对。创建一个键"framework"和一个值"Flask"

http://127.0.0.1:5000/query-example?language=Python&framework=Flask

如果您想要更多,请继续添加与号和键值对。创建一个键"website"和一个值"DigitalOcean"

http://127.0.0.1:5000/query-example?language=Python&framework=Flask&website=DigitalOcean

要访问这些值,您仍将使用request.args.get()request.args[]让我们使用两者来演示丢失密钥时会发生什么。修改query_example路由,将结果的值赋给变量,然后显示:

@app.route('/query-example')
def query_example():
    # if key doesn't exist, returns None
    language = request.args.get('language')

    # if key doesn't exist, returns a 400, bad request error
    framework = request.args['framework']

    # if key doesn't exist, returns None
    website = request.args.get('website')

    return '''
              <h1>The language value is: {}</h1>
              <h1>The framework value is: {}</h1>
              <h1>The website value is: {}'''.format(language, framework, website)

然后,运行应用程序并导航到 URL:

http://127.0.0.1:5000/query-example?language=Python&framework=Flask&website=DigitalOcean

浏览器应显示以下消息:

Output
The language value is: Python The framework value is: Flask The website value is: DigitalOcean

language从 URL 中删除密钥:

http://127.0.0.1:5000/query-example?framework=Flask&website=DigitalOcean

None当未提供值时,浏览器应显示以下消息language

Output
The language value is: None The framework value is: Flask The website value is: DigitalOcean

framework从 URL 中删除密钥:

http://127.0.0.1:5000/query-example?language=Python&website=DigitalOcean

浏览器应该会遇到错误,因为它需要一个值framework

Output
werkzeug.exceptions.BadRequestKeyError werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand. KeyError: 'framework'

现在您了解了处理查询字符串。让我们继续下一个类型的传入数据。

使用表单数据

表单数据来自已作为 POST 请求发送到路由的表单。因此,不是在 URL 中看到数据(除了通过 GET 请求提交表单的情况),表单数据将在后台传递给应用程序。即使您无法轻松看到传递的表单数据,您的应用程序仍然可以读取它。

为了演示这一点,修改form-example路由app.py以接受 GET 和 POST 请求并返回一个表单:

应用程序
# allow both GET and POST requests
@app.route('/form-example', methods=['GET', 'POST'])
def form_example():
    return '''
              <form method="POST">
                  <div><label>Language: <input type="text" name="language"></label></div>
                  <div><label>Framework: <input type="text" name="framework"></label></div>
                  <input type="submit" value="Submit">
              </form>'''

然后,运行应用程序并导航到 URL:

http://127.0.0.1:5000/form-example

浏览器应该显示一个包含两个输入字段的表单 – 一个用于language,一个用于framework– 和一个提交按钮。

关于这个表单最重要的事情是它对生成表单的同一路由执行 POST 请求。将在应用程序中读取的键都来自name我们表单输入上属性。在这种情况下,languageframework是输入的名称,因此您可以访问应用程序中的名称。

在视图函数中,您需要检查请求方法是 GET 还是 POST。如果是 GET 请求,则可以显示表单。否则,如果它是 POST 请求,那么您将需要处理传入的数据。

使用以下代码修改form-example路由app.py

应用程序
# allow both GET and POST requests
@app.route('/form-example', methods=['GET', 'POST'])
def form_example():
    # handle the POST request
    if request.method == 'POST':
        language = request.form.get('language')
        framework = request.form.get('framework')
        return '''
                  <h1>The language value is: {}</h1>
                  <h1>The framework value is: {}</h1>'''.format(language, framework)

    # otherwise handle the GET request
    return '''
           <form method="POST">
               <div><label>Language: <input type="text" name="language"></label></div>
               <div><label>Framework: <input type="text" name="framework"></label></div>
               <input type="submit" value="Submit">
           </form>'''

然后,运行应用程序并导航到 URL:

http://127.0.0.1:5000/form-example

填写language值为字段和值为Pythonframework字段Flask然后,按提交

浏览器应显示以下消息:

Output
The language value is: Python The framework value is: Flask

现在您了解了处理表单数据。让我们继续下一个类型的传入数据。

使用 JSON 数据

JSON 数据通常由调用路由的进程构建。

一个示例 JSON 对象如下所示:

{
    "language" : "Python",
    "framework" : "Flask",
    "website" : "Scotch",
    "version_info" : {
        "python" : "3.9.0",
        "flask" : "1.1.2"
    },
    "examples" : ["query", "form", "json"],
    "boolean_test" : true
}

这种结构可以允许传递更复杂的数据,而不是查询字符串和表单数据。在示例中,您会看到嵌套的 JSON 对象和一组项目。Flask 可以处理这种格式的数据。

修改form-example路由app.py以接受 POST 请求并忽略其他请求,如 GET:

应用程序
@app.route('/json-example', methods=['POST'])
def json_example():
    return 'JSON Object Example'

与用于查询字符串和表单数据的 Web 浏览器不同,为了本文的目的,要发送 JSON 对象,您将使用Postman向 URL 发送自定义请求。

注意:如果您需要在 Postman 界面导航以获取请求方面的帮助,请参阅官方文档

在 Postman 中,添加 URL 并将类型更改为POST在 body 选项卡上,更改为raw从下拉列表中选择JSON

这些设置是必需的,以便 Postman 可以正确发送 JSON 数据,并且您的 Flask 应用程序将了解它正在接收 JSON:

POST http://127.0.0.1:5000/json-example
Body
raw JSON

接下来,将之前的 JSON 示例复制到文本输入中。

发送请求,你应该得到"JSON Object Example"响应。这是相当反气候的,但在意料之中,因为处理 JSON 数据响应的代码尚未编写。

要读取数据,您必须了解 Flask 如何将 JSON 数据转换为 Python 数据结构:

  • 任何对象都会被转换为 Python 字典。{"key" : "value"}在 JSON 中对应于somedict['key'],它在 Python 中返回一个值。
  • JSON 中的数组被转换为 Python 中的列表。由于语法相同,这里有一个示例列表:[1,2,3,4,5]
  • JSON 对象中引号内的值在 Python 中变为字符串。
  • 布尔truefalse成为TrueFalsePython编写的。
  • 最后,没有引号的数字在 Python 中变成了数字。

现在让我们处理读取传入 JSON 数据的代码。

首先,让我们使用 .json 将 JSON 对象中的所有内容分配给一个变量request.get_json()

request.get_json()将 JSON 对象转换为 Python 数据。让我们将传入的请求数据分配给变量,并通过对json-example路由进行以下更改来返回它们

应用程序
# GET requests will be blocked
@app.route('/json-example', methods=['POST'])
def json_example():
    request_data = request.get_json()

    language = request_data['language']
    framework = request_data['framework']

    # two keys are needed because of the nested object
    python_version = request_data['version_info']['python']

    # an index is needed because of the array
    example = request_data['examples'][0]

    boolean_test = request_data['boolean_test']

    return '''
           The language value is: {}
           The framework value is: {}
           The Python version is: {}
           The item at index 0 in the example list is: {}
           The boolean value is: {}'''.format(language, framework, python_version, example, boolean_test)

请注意您如何访问不在顶层的元素。['version']['python']使用是因为您正在输入嵌套对象。并且['examples'][0]用于访问示例数组中的第 0 个索引。

如果随请求发送的 JSON 对象没有可在您的视图函数中访问的键,则请求将失败。如果您不希望在密钥不存在时它失败,则必须在尝试访问它之前检查该密钥是否存在。

应用程序
# GET requests will be blocked
@app.route('/json-example', methods=['POST'])
def json_example():
    request_data = request.get_json()

    language = None
    framework = None
    python_version = None
    example = None
    boolean_test = None

    if request_data:
        if 'language' in request_data:
            language = request_data['language']

        if 'framework' in request_data:
            framework = request_data['framework']

        if 'version_info' in request_data:
            if 'python' in request_data['version_info']:
                python_version = request_data['version_info']['python']

        if 'examples' in request_data:
            if (type(request_data['examples']) == list) and (len(request_data['examples']) > 0):
                example = request_data['examples'][0]

        if 'boolean_test' in request_data:
            boolean_test = request_data['boolean_test']

    return '''
           The language value is: {}
           The framework value is: {}
           The Python version is: {}
           The item at index 0 in the example list is: {}
           The boolean value is: {}'''.format(language, framework, python_version, example, boolean_test)

运行应用程序并使用 Postman 提交示例 JSON 请求。在响应中,您将获得以下输出:

Output
The language value is: Python The framework value is: Flask The Python version is: 3.9 The item at index 0 in the example list is: query The boolean value is: false

现在您了解处理 JSON 对象了。

结论

在本文中,您使用三个接受查询字符串、表单数据或 JSON 对象的路由构建了一个 Flask 应用程序。

此外,请记住,所有方法都必须解决在丢失密钥时优雅失败的反复出现的问题。

警告:本文未涉及的一个主题是清理用户输入。清理用户输入将确保应用程序读取的数据不会导致意外失败或绕过安全措施。

如果您想了解有关 Flask 的更多信息,请查看我们的 Flask 主题页面以获取练习和编程项目。

觉得文章有用?

点个广告表达一下你的爱意吧 !😁