一、Flask 环境安装
要使用 Flask 框架,需要先通过命令行 pip 工具安装 Flask。
pip install flask
以下是一个简单的 Flask 入门示例,演示了如何创建一个基本的 Web 应用程序:
from flask import Flask
# 创建 Flask 应用程序实例
app = Flask(__name__)
# 定义路由和视图函数
@app.route("/")
def hello():
return "Hello Flask!"
上述示例代码创建了一个最简单的 Flask 应用程序。
- 导入 Flask 模块:首先,我们需要导入 Flask 模块,以便使用 Flask 框架提供的功能。
- 创建应用程序实例:通过实例化 Flask 类并传入
__name__
参数,我们创建了一个 Flask 应用程序的实例。__name__
是一个特殊变量,它表示当前模块的名称。 - 定义路由和视图函数:使用
@app.route()
装饰器来定义路由,指定 URL 路径和对应的视图函数。在上面的示例中,我们定义了根路径'/'
的视图函数hello()
。 - 视图函数:视图函数是处理请求并返回响应的函数。在上面的示例中,
hello()
函数返回字符串'Hello, Flask!'
,它将作为浏览器中访问根路径时的响应。
Flask 运行使用
- 代码调用
app.run()
- 命令行运行
- bash(mac/linux)
- cmd(windows)
- powershell(windows)
在代码中可以通过使用 app.run()
方法运行应用程序。默认情况下,应用程序会运行在本地服务器上,监听 5000 端口。
# 运行应用程序
if __name__ == '__main__':
app.run()
可以通过访问 http://localhost:5000/
在浏览器中查看结果。
或者也可以在命令行中启动应用程序。Flask 框架自带了一个运行工具叫做flask run
,可以在项目目录下使用命令行命令flask run
来启动 Flask 项目。这个命令会启动一个开发服务器,并在浏览器中打开项目页面。
启动前可以通过设定环境变量 FLASK_APP=文件名
来表示将要运行的应用是哪个,然后运行 flask run
来启动该应用。
不同的操作系统设置环境变量的命令是不同的,具体参考以下命令:
# linux/mac: 命令行运行
$ export FLASK_APP=hello
$ flask run
# windows: 命令运行
> set FLASK_APP=hello
> flask run
二、接口路由技术
什么是路由
路由是将 URL 地址与应用程序中的函数相映射的过程。当用户在浏览器中输入特定的 URL 地址时,Flask 会调用与该地址相匹配的函数并返回相应的结果。
路由的应用场景
在 Web 应用程序都通过路由技术使用 URL 链接来控制网页显示的内容,只要知道 URL 链接,即使没有主页导航也可以直接访问所需网页。
通过 Flask 实现路由
路由类型 | 实现方式 |
---|---|
基本路由 | @app.route('/') |
动态路由 | @app.route('/user/<username>') |
限定类型 | @app.route('/post/<int:post_id>') |
在 Flask 中,可以使用 @app.route()
装饰器来定义路由。路由决定了用户请求的 URL 路径与对应的视图函数之间的关系。
基本路由
基本路由定义方式为:
from flask import Flask
# 创建 Flask 应用程序实例
app = Flask(__name__)
# 定义基本路由
@app.route("/")
def index():
return "Home Page"
@app.route("/about")
def about():
return "About Page"
# 运行应用程序
if __name__ == '__main__':
app.run()
在上述示例中,@app.route('/')
和 @app.route('/about')
分别定义了根路径 '/'
和 /about
的路由。当用户访问这些路径时,Flask 会调用对应的视图函数并返回相应的内容。
@app.route('/')
访问地址为 http://127.0.0.1:5000/
,@app.route('/about')
访问地址为 http://127.0.0.1:5000/about
。
动态路由
URL 中某些地方存在可变部分,为动态的 URL,Flask 支持这种动态 URL。
动态路由是通过尖括号 <>
实现的,放在尖括号里面的部分为动态部分,即在装饰器 route 传入 <>
部分,定义视图函数时,将该 <>
里面的内容作为参数传入到函数里面即可。
比如路由 /user/Harry
后面想要根据不同的用户名,返回不同的数据。这种情况可以用变量来代替名字部分:@app.route('/user/<username>')
。
这时 username 传入不同的值时,比如依次传入 Harry、Ron、Hermione,那么对应的路由就变为:/user/Harry
、/user/Ron
、/user/Hermione
。
# 定义动态路由
@app.route("/user/<username>")
def user_info(username):
return f"User {username} is select info."
访问:http://127.0.0.1:5000/user/Ron
查看服务端日志,会有一条返回信息:User Ron is select info.
。
限定类型
如果希望限定输入的动态字段的类型,可以使用 <类型:变量名>
来实现,例如如果希望某个字段只能是整数,那么可以写为 /user/<int:user_id>
。
# 限定类型的动态路由
# 类型限定为整型
@app.route("/user/<int:user_id>")
def user_id(user_id):
# 展示给定的用户 ID,ID 为整型
return f"User ID is {user_id}"
# 类型限定为 path(可以包含 /)
@app.route('/path/<path:sub_path>')
def show_subpath(sub_path):
# 展示 path 后的子路由
return f'Subpath is {sub_path}'
# 动态路由
@app.route("/userinfo/<string:username>/")
def hogw(username):
logger.info(f"这是{username}同学的个人信息")
return f"这是{username}同学的个人信息"
if __name__ == '__main__':
# 启动flask服务
# 轮询等待的方式,等待浏览器发来请求
# 会一直接受请求,知道程序停止
app.run()
Flask 支持在路由上使用的类型有 int、float、string、path。path 类型是字符串的一种,不同的是它可以包含正斜线。
路由规则
Flask 的 URL 规则基于 Werkzeug 的路由模块。可以确保形成的 URL 是唯一的,并且基于 Apache 规定的先例。
@app.route('/about')
def about():
return 'About Page'
@app.route('/hogwarts/')
def hello_hogwarts():
return 'Hello Hogwarts'
if __name__ == '__main__':
app.run()
这两个路由定义的例子看起来类似,其实是不一样的。
在第二个例子中,路由的尾部使用斜杠 (/)。因此,它成为一个规范的URL。这时 Flask 会自动进行重定向。当在浏览器的地址栏中不输入 /
时,会自动在尾部加上一个斜杠。也就是在浏览器的地址栏中输入 /
和不输入 /
的效果是一样的。
而第一个例子中,路由的尾部没有 /
。那么访问的时候,在浏览器的地址栏中不能输入 /
,否则会产生 “Not Found” 的错误。这样可以保持 URL 唯一。
三、请求与响应 - 请求方法
接口常用请求方法
Flask 框架支持常见的 HTTP 请求方法,最常用的请求方法为:
请求 | 说明 |
---|---|
GET | 获取服务器资源 |
POST | 新增服务器资源 |
PUT | 更新服务器资源(客户端提供改变后的完整资源) |
DELETE | 删除服务器资源 |
这些请求方式都是去操作资源的。
- GET:一般是从 URI 中从 服务器中获取资源(比如获取用例列表,比如,获取用户信息等等),但一般 GET 是存在不安全性的,如果有敏感信息,会使用 POST。
- POST: 主要用于将【数据发送到服务器】创建或更新资源。注意,POST 对数据长度是没有限制的,GET 会有限制,这是因为某些浏览器对请求的 URL 长度有限制。
- PUT:也是用于将 【数据发送到服务器】创建或更新资源。
- DELETE:用来删除指定的资源。
Flask 支持的请求方法通过在路由定义时使用 methods
参数进行指定。可以指定多个请求方法,以列表的形式传递给 methods
参数。
下面分别演示这四种请求的用法。
GET 请求
默认情况下,Flask 路由定义的视图函数只支持 GET 请求。如果需要支持其他请求方法,需要显式地指定 methods
参数。
from flask import Flask
# 创建 Flask 应用程序实例
app = Flask(__name__)
# get 请求
@app.route("/get")
def get():
return f"Method is GET."
@app.route("/get_method", methods=["GET"])
def get_method():
return f"GET method success."
if __name__ == '__main__':
app.run()
POST 请求
from flask import Flask
# 创建 Flask 应用程序实例
app = Flask(__name__)
# post 请求
@app.route("/post", methods=["POST"])
def post():
return f"Method is POST."
if __name__ == '__main__':
app.run()
PUT 请求
from flask import Flask
# 创建 Flask 应用程序实例
app = Flask(__name__)
# put 请求
@app.route("/put", methods=["PUT"])
def put():
return f"Method is PUT."
if __name__ == '__main__':
app.run()
DELETE 请求
from flask import Flask
# 创建 Flask 应用程序实例
app = Flask(__name__)
# delete 请求
@app.route("/delete", methods=["DELETE"])
def delete():
return f"Method is DELETE."
if __name__ == '__main__':
app.run()
from flask import Flask
app = Flask(__name__)
# methods是一个列表类型,可以添加多种请求方式get post put delete
@app.route("/cases", methods=["get"])
def get_case():
return {"cede": 0, "msg": "get success"}
@app.route("/cases", methods=["post"])
def post_case():
return {"cede": 0, "msg": "post success"}
@app.route("/cases", methods=["put"])
def put_case():
return {"cede": 0, "msg": "put success"}
@app.route("/cases", methods=["delete"])
def delete_case():
return {"cede": 0, "msg": "delete success"}
if __name__ == '__main__':
app.run()
四、请求与响应 - 处理请求数据
request 对象
当浏览器去访问一个地址时,HTTP 协议会向后台传递一个 request 对象。这个 request 对象包含请求头、请求参数、以及请求方式。后台可以取到 request,然后进行逻辑处理。
在 Flask 中,可以使用 request 对象来处理请求数据。request 对象提供了访问请求数据的方法和属性。
request 的常用属性/方法
以下是一些常见的处理请求数据的方法:
属性/方法 | 说明 |
---|---|
args | 记录请求中的查询参数 |
json | 记录请求中的 json 数据 |
files | 记录请求上传的文件 |
form | 记录请求中的表单数据 |
method | 记录请求使用的 HTTP 方法 |
url | 记录请求的 URL 地址 |
host | 记录请求的域名 |
headers | 记录请求的头信息 |
普通请求参数处理
如果一个 GET 请求在 URL 中拼接了请求参数,可以使用 request.args
来获取 GET 请求中携带的请求参数。request.args
是一个字典,可以通过键名来获取参数的值。
from flask import Flask, request
# 创建 Flask 应用程序实例
app = Flask(__name__)
@app.route('/user')
def get_user():
# 获取 URL 中的请求参数
url_param = request.args
# 查看获取到的请求参数的类型
print(type(url_param))
# 获取请求参数中的 username 对应的值
username = url_param.get('username')
return f'Hello, {username}!'
# 运行应用程序
if __name__ == '__main__':
app.run()
访问 /user?username=John
,将返回 'Hello, John!'
。
查看服务端日志信息,可以看到 request.args
取到的值的数据类型为 werkzeug.datastructures.structures.ImmutableMultiDict,也是一个可迭代的对象,访问方法和基础的字典类似。想要获取这个字典中 username
对应的值,可以直接使用 get()
方法。
@app.route("/login/", methods=["get"])
def login():
logger.info(f"请求参数为:{request.args}")
result = request.args
a = result.get("a")
b = result.get("b")
print(f"a={a}, b={b}")
return {"code": 0, "msg": "get success"}
JSON 请求体处理
如果是 POST 或者 PUT 相关的请求,需要带有 JSON 数据格式,可以使用 request.json
来获取 POST 请求中的 JSON 数据。request.json
会解析请求的 JSON 数据,并返回一个包含解析后的数据的字典,然后可以根据需要获取特定的字段值。
from flask import Flask, request
# 创建 Flask 应用程序实例
app = Flask(__name__)
@app.route('/data', methods=['POST'])
def process_data():
# 获取 JSON 格式请求体
data = request.json
# 查看获取到的请求参数的类型
print(type(data))
# 获取请求体中对应字段的值
name = data.get('name')
age = data.get('age')
return f'Name: {name}, Age: {age}'
# 运行应用程序
if __name__ == '__main__':
app.run()
提交 JSON 格式请求体,请求体中包含姓名和年龄,将返回姓名和年龄的信息。
@app.route("/regist", methods=["post"])
def post_regist():
logger.info(request.json)
return {"code": 0, "msg": "post success"}
表单请求体处理
如果是 POST 相关的请求,需要带有 form 表单格式数据格式,可以使用 request.form
来获取 POST 请求中的表单数据。request.form
是一个字典,可以通过键名来获取表单字段的值。
from flask import Flask, request
# 创建 Flask 应用程序实例
app = Flask(__name__)
@app.route('/login', methods=['POST'])
def login():
# 获取表单格式请求体
user_info = request.form
# 查看获取到的请求参数的类型
print(type(user_info))
# 获取请求体中对应字段的值
username = user_info.get('username')
password = user_info.get('password')
return f'Welcome, {username}!'
# 运行应用程序
if __name__ == '__main__':
app.run()
通过提交包含用户名和密码的表单,将返回欢迎信息。
# 表单接口,注册:用户名、密码、确定密码、邮箱
@app.route("/regist1", methods=["put"])
def put_regist():
name = request.form.get("name")
password = request.form.get("password")
password_confirm = request.form.get("password_confirm")
email = request.form.get("email")
logger.info(request.form)
logger.info(f"注册的用户信息为:name:{name}, password:{password}, password_confirm:{password_confirm}, email:{email}")
return {"code": 0, "msg": "put success"}
文件请求体处理
如果页面上需要提交一个图片,或者上传一个文件到后端服务器,可以使用 request.files
来获取请求中包含的文件。request.files
是一个字典,每个上传的文件都会存储在这个字典里。可以通过 file
这个 key 来获取其中的文件对象。
已上传的文件存储在内存或是文件系统中一个临时的位置。它有一个 save()
方法,这个方法允许把文件保存到服务器的文件系统上。
如果想知道上传前文件在客户端的文件名是什么,可以访问 filename
属性。但这个值是可以伪造的。如果要把文件按客户端提供的文件名存储在服务器上,需要把它传递给 Werkzeug 提供的 secure_filename()
函数。这个函数可以用来确保文件名是安全的。
from flask import request
from werkzeug import secure_filename
# 创建 Flask 应用程序实例
app = Flask(__name__)
@app.route('/upload', methods=['POST'])
def upload_file():
# 获取文件格式请求体
file = request.files
# 查看获取到的请求参数的类型
print(type(file))
# 获取请求体中对应字段的值
f = file.get("file")
# 保存文件
# 需要提前创建 uploads 目录,secure_filename 可以确保文件名安全
f.save('./uploads/' + secure_filename(f.filename))
return f'File {f.filename} is saved!'
# 运行应用程序
if __name__ == '__main__':
app.run()
# 处理客户端发来的文件请求
@app.route("/file/", methods=["post"])
def post_file():
file_obj = request.files.get("file")
logger.info(file_obj)
file_name = file_obj.filename
logger.info(f"文件名为:{file_name}")
file_obj.save("./logo1.png")
return {"code": 0, "msg": "post success"}
import requests
def test_file():
url = "http://127.0.0.1:5000/file"
file = {"file": open("/Users/mei/Downloads/timg.jpeg", "rb")}
r = requests.post(url, files=file)
assert r.status_code == 200
通过提交包含文件的请求体,将返回文件保存息。
其他请求参数处理
如果在进行业务处理的时候,需要根据不同的请求 URL、域名、请求参数或者请求头信息进行不同场景的判断,则可以使用以下方法获取对应的值。
from flask import request
from werkzeug import secure_filename
# 创建 Flask 应用程序实例
app = Flask(__name__)
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
# 获取请求 URL
r_url = request.url
# 获取请求域名
r_host = request.host
# 获取请求头信息
r_headers = request.headers
# 获取请求方法
r_method = request.method
print(r_url, r_host, r_headers, r_method)
# 获取文件请求体
r_file = request.files
# 判断请求方法为 POST
if r_method == 'POST':
# 判断请求头中包含 My-Header 字段并且值为 hogwarts
if r_headers.get('My-Header') == "hogwarts":
# 保存文件
f = r_file.get("file")
f.save('./uploads/' + secure_filename(f.filename))
return f'File {f.filename} is saved! URL is {r_url}, host is {r_host}'
return f"My-Header is missing!"
return f"Method is wrong!"
# 运行应用程序
if __name__ == '__main__':
app.run()
这样就可以校验请求方法、请求头信息,然后再完成对应的业务逻辑处理了。
五、请求与响应 - 处理响应信息
针对于后端服务,需要针对请求返回对应的响应信息。
响应信息可以响应很多类型的信息类型。常见的比如文本类型,还有非常通用的 JSON 数据。
在 Flask 中,可以使用视图函数来处理接口请求并生成相应的响应。而且 Flask 提供了多种方式来构建和返回接口响应。
接口响应常见类型
- 文本型
- 元组
- JSON
- HTML
- 额外数据
返回文本类型
首先来看最简单的类型,返回一个文本数据。
比如现在编写一个接口,设定路由为 /text
,请求方法为默认的 GET 请求。返回一串文本信息。
from flask import Flask
# 创建 Flask 应用程序实例
app = Flask(__name__)
# 定义路由和视图函数
@app.route('/text')
def text_res():
return '返回文本'
# 运行应用程序
if __name__ == '__main__':
app.run()
示例中,视图函数 text_res()
直接返回一个字符串 '返回文本'
,Flask 将自动将其封装成一个纯文本响应并发送给客户端。打开浏览器,就可以看到接口返回的文本内容。
此外,打开浏览器开发者工具 Network 面板查看这个接口,可以注意到 Response Headers
中的Content-Type
是 text/html; charset=utf-8
。
返回元组类型
除了文本,接口还可以返回元组格式。
元组格式包含 3 个参数类型。第一个是 response 对象,第二个是响应状态码,第三个是响应头信息。也可以只填写 2 个返回信息。比如 (response, status)
结合,还有 (response, headers)
结合。
例如:如果 3 个返回数据都添加响应信息。
from flask import Flask
# 创建 Flask 应用程序实例
app = Flask(__name__)
@app.route('/tuple')
def tuple_res():
return "你好呀", 200, {"hogwarts": "Harry"}
# 运行应用程序
if __name__ == '__main__':
app.run()
可以看到响应状态码为 200,响应头信息中包含了 Hogwarts 这个字段。
返回 JSON
在前后端分离开发的实践中,后端提供的接口响应信息基本都为通用的 JSON 格式。
返回 JSON 类型的响应数据有两种方法。
- 第一种是使用
jsonify()
方法,此方法支持,直接传入一个字典,也支持通过关键字参数传递。
# 返回json
from flask import Flask, jsonify
# 创建 Flask 应用程序实例
app = Flask(__name__)
@app.route('/json')
def get_json():
# jsonify({'status': 0})
return jsonify(status=1, name="lily", age=20)
# 运行应用程序
if __name__ == '__main__':
app.run()
- 第二种方法就是直接返回字典,在 Flask 1.1 版本之后,直接返回 python 的字典类型时,Flask 会调用
jsonify()
方法。
# 返回字典
from flask import Flask
# 创建 Flask 应用程序实例
app = Flask(__name__)
# 定义路由和视图函数
@app.route('/dict')
def get_dict():
return {'status': 0}
# 运行应用程序
if __name__ == '__main__':
app.run()
以上 /json
和 /dict
路由的响应信息的 Content-Type
均为 application/json
。
返回 HTML
接口还可以直接返回 HTML。返回 HTML 主要使用的是模板渲染技术。
from flask import Flask, render_template
# 创建 Flask 应用程序实例
app = Flask(__name__)
@app.route('/html')
def get_html():
# 调用render_template方法,传入html 文件的名称。
# 注意html文件必须在 templates 目录下
return render_template('demo.html')
# 运行应用程序
if __name__ == '__main__':
app.run()
可以在 templates 目录下新建 demo.html 文件。
<!--
html文件必须在templates目录下
/application.py
/templates
/demo.html
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Hogwarts</title>
</head>
<body>
<h1>霍格沃兹测试开发</h1>
</body>
</html>
浏览器中访问 /html
路由,发现页面中展示了 霍格沃兹测试开发
。
返回额外数据
在构造响应的过程中,除了构造响应体,响应头,响应状态码等,可能还要添加其他的响应信息。比如需要添加 cookie,则可以使用 make_response()
方法。
from flask import Flask, render_template, make_response
# 创建 Flask 应用程序实例
app = Flask(__name__)
# 定义路由和视图函数
@app.route('/')
def index():
resp = make_response(render_template('demo.html'))
# 设置cookie
resp.set_cookie('username', 'the username')
# 设置响应头信息
resp.headers["hogwarts"] = "Hary"
return resp
# 运行应用程序
if __name__ == '__main__':
app.run()
浏览器中访问 http://127.0.0.1:5000
路由,发现页面中展示 霍格沃兹测试开发
。且响应头信息中包含 Hogwarts 字段,值为 Hary。Set-Cookie 中包含设置的 Cookie 信息。
六、测试平台环境配置
在 Flask 中,可以使用 app.run()
方法来运行应用程序并设置要监听的主机和端口。
app.run()
方法默认会监听在默认的主机地址 '127.0.0.1'
(或 'localhost'
)和端口 5000
上。可以通过访问 http://localhost:5000/
来访问应用程序。
监听主机
-
app.run()
设置 host 参数指定要监听的主机地址:-
127.0.0.1
只能本机访问。 -
0.0.0.0
服务发布到局域网。
-
app.run(host="0.0.0.0")
当 host 值为 '0.0.0.0'
,这表示应用程序将监听所有可用的网络接口。可以通过访问 http://<your-ip>
来访问应用程序,其中 <your-ip>
是运行应用程序的主机的 IP 地址。
监听端口
-
app.run()
设置 port 参数(默认端口号 5000)
app.run(host="0.0.0.0", port=5050)
app.run()
使用 port
参数指定要监听的端口。默认端口为 5000
,可以改为其他需要的端口。
Debug 模式
在 Flask 中,可以通过设置调试模式(Debug Mode)来启用或禁用调试功能。调试模式是开发阶段常用的工具,它提供了一些有用的功能,以帮助开发者进行调试和错误排查。
-
app.run()
设置debug=True
(默认是 production)
调试模式的作用
- 显示详细的错误信息:在调试模式下,当应用程序出现错误时,Flask 会显示详细的错误信息,包括错误堆栈跟踪。这对于定位和修复错误非常有帮助。
- 自动重新加载代码:调试模式下,如果你修改了应用程序的代码文件,Flask 会自动重新加载修改后的代码,而无需手动重启应用程序。这样可以加快开发的迭代速度,节省重启服务器的时间。
- 支持实时调试器:调试模式下,Flask 提供了一个实时调试器(Debugger),可以在浏览器中显示源代码和调试信息,并允许你在运行时进行断点调试和变量查看。
app.run(host="0.0.0.0", port=5050, debug=True)
要注意的是,在生产环境中,不建议使用调试模式,因为它会暴露应用程序的详细信息,并且自动重新加载代码可能会导致安全风险。调试模式应仅在开发阶段使用,并且在部署到生产环境之前,务必禁用调试模式。
因此,调试模式是一个方便的开发工具,它提供了错误信息的显示、自动重新加载代码和实时调试器等功能,可以加速开发过程和调试错误。但在生产环境中应该禁用调试模式以确保应用程序的安全性和性能。