介绍
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
文件。导入Flask
和request
对象。并为query-example
、form-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')
,如果language
URL 中不存在密钥,应用程序将继续运行。在这种情况下,该方法的结果将为None
。
通过调用request.args['language']
,如果language
URL 中不存在密钥,应用程序将返回 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
浏览器应显示以下消息:
OutputThe 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
浏览器应显示以下消息:
OutputThe 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
:
OutputThe 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
:
Outputwerkzeug.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
我们表单输入上的属性。在这种情况下,language
和framework
是输入的名称,因此您可以访问应用程序中的名称。
在视图函数中,您需要检查请求方法是 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
值为的字段和值为Python
的framework
字段Flask
。然后,按提交。
浏览器应显示以下消息:
OutputThe 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 中变为字符串。
- 布尔
true
并false
成为True
与False
Python编写的。 - 最后,没有引号的数字在 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 请求。在响应中,您将获得以下输出:
OutputThe 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 主题页面以获取练习和编程项目。