1 知识储备
在学习Flask
应用之前,让我们先了解一些术语。
1.1 Web服务器
- Web服务器是一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,可以向浏览器等Web客户端提供文档,也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载
- 目前主流的
Web服务器
有:Tomcat
、Nginx
和IIS
1.2 Web应用程序
- Web应用程序一般是指可以通过
Web
访问的应用程序
1.3 认识WSGI-Web服务器网关接口
WSGI
,是Python
语言定位的Web
服务器与Web
应用程序或框架之间的一种简单而通用的接口WSGI
没有官方实现,更像是一种协议,主要遵循这种协议,WSGI
应用程序都可以在任何服务器上部署、运行,反之亦然WSGI
分为两个部分,一个是“服务器”或者“网关”,一个是“应用程序”或者“应用框架”。在处理WSGI
请求时,服务器会为应用程序提供环境信息以及一个回调函数;当应用程序完成处理请求后,通过回调函数将结果信息返回给服务器
2 Flask应用基本结构
2.1 Flask初始化
实例化Flask
对象是编写Flask
应用程序的第一步。实例化的Flask
即可实例化一个WSGI
应用程序,并充当核心对象。该过程需要传入应用程序的模块或包的名称。一旦该对象成功,它将成为View Function
、URL Rules
和Template Configuration
等的核心注册对象。
Flask
初始化很简单,只需传入一个参数,即应用程序主模块或包的名称,一般传入__name__
即可,示例代码如:
from flask import Flask
app = Flask(__name__)
2.1.1 理解Flask传入的第一个参数
Flask
应用程序可根据这个参数,从当前包或者包含当前模块(.py
文件)的文件夹内查询资源;另外,Flask
的扩展也可根据这个参数优化调试信息等等。
官网建议,如果使用一个单独的模块(即:一个独立的.py
文件),传入__name__
即可;如果使用一个包(含__init__.py
文件的文件夹),通常建议此处填入包的名称;如果这种情况仍然传入__name__
,程序也可以正常运行,不过在测试环境中,某个扩展可能会出现意想不到的问题。
2.2 路由
2.2.1 什么是路由
客户端将请求发送给Web
服务器,然后Web
服务器将请求转发给Flask
应用示例。而,应用示例接收到URL
请求后需要知道它该运行哪些代码,所需要保存URL
和函数的映射对应关系,而存储这些关系的就是路由。
2.2.2 定义路由
Flask
中定义路由有两种方式:
- 简便的方式,使用应用实例提供的
app.route
装饰器,如下:
@app.rout("\")
def index():
return '<h1>Hello World</h1>'
- 传统的方式,使用
app.add_url_rule
方法,该方法接收3个参数:URL
、断点(endpoint)和视图函数,如下:
def index():
return '<h1>Hello World</h1>'
app.add_url_rule('/', 'index', index)
处理类似index
这种入站请求的函数统称为视图函数
2.2.3 定义动态路由
Flask
支持动态路由,只需在URL
中使用对应的句法即可,例如/user/<name>
,其中<>
中的内容就是动态的,其他内容是该URL
中静态部分,Flask
会将动态部分作为参数传入给视图函数。
Flask
中动态部分默认是字符串类型,也可以显示定义其他类型,例如:int
、float
和path
,其中,path
类型是一种特殊的字符串,它可以包含正斜线。
2.3 Web开发服务器
Flask
中自带Web开发服务器,可通过flask run
命令启动,需提前配置FLASK_APP
环境变量,给该命令指定从哪个Python
脚本中寻找应用示例。
以运行hello.py
这个文件为例
# Linux和MacOS
export FLASK_APP=hello.py
flask run
# Windows
set FLASK_APP=hello.py
flask run
Web
开发服务器启动后,便开始轮训,处理请求,直到该服务器停止。
除了使用flask run
的方式,也可以使用编程的方式启动:调用app.run
方法。在之前旧版本中,若想启动应用,需要运行应用的主脚本,该主脚本需要在其尾部增加如下内容:
if __name__ == '__main__':
app.run()
现有版本中,常使用flask run
命令启动,不过在单元测试中,也可使用编程方式启动应用。
2.4 调试模式
Flask
调试模式默认会加载两个便利的工具:重载器和调试器。
- 重载器
启用重载器后,Flask
会监听项目中所有的源代码文件,发现变动后自动重启服务器。
- 调试器
调试器是基于Web
工具,当应用跑出未处理的异常时,它会出现在浏览器中。
启用调试模式方式如下:
- 当使用
flask run
命令
在使用flask run
之前设定FLASK_DEBUG=1
环境变量
- 当使用
app.run()
方式
当使用这种方式时,需传递参数debug=True
,即app.run(debug=True)
2.5 请求-响应循环
2.5.1 应用和请求上下文
Flask
从客户端接收到请求后,会使用临时上下文将某些对象变为全局访问,以便让视图函数能够访问,从而处理这些请求,其调用方式如下:
from flask import request
需要提醒的是,request
只是被当做全局变量访问,但事实上肯定不会是全局变量。因为,在多线程Web
服务器中,多个线程同时处理不同客户端发送的请求时,每个线程接收到的request
对象必然是不同的。
在Flask
中,上下文可分为应用上下文和请求上下文,如下:
变量名 | 上下文 | 说明 |
---|---|---|
current_app | 应用上下文 | 当前应用的应用实例 |
g | 应用上下文 | 处理请求时用作临时存储的对象,每次请求都会重设这个变量 |
request | 请求上下文 | 请求对象,封装了客户端发出的HTTP 请求中内容 |
session | 请求上下文 | 用户会话,值为一个字典,存储请求之间需要“记住”的值 |
Flask
在分派请求之前激活(或者推送)应用和请求上下文,请求处理完成之后再将其删除。也就是,应用上下文被推送之后,就可以在当前线程中使用current_app
和g
变量;请求上下文被推送之后,就可以在当前线程中使用request
和session
变量。如果在没有激活应用上下文或者请求上下文之前使用这些变量,将会导致错误。
request
对象常用属性和方法
属性或方法 | 说明 |
---|---|
form | 一个字典,存储请求提交的所有表单字段 |
args | 一个字典,存储通过URL查询字符串传递的所有参数 |
values | 一个字典,form 和args 的合集 |
cookies | 一个字典,存储请求的所有的cookie |
headers | 一个字典,存储请求所有的HTTP 首部 |
files | 一个字典,存储请求上传的所有文件 |
get_data() | 返回请求主体缓冲的数据 |
get_json() | 返回一个字典,包含解析请求主体后得到的JSON |
blueprint | 处理请求的Flask 蓝本的名称 |
endpoint | 处理请求的Flask 端点的名称,Flask 会将视图函数的名称用作路由端点的名称 |
method | HTTP 请求方法,例如GET 和POST |
scheme | URL 方案,http 或https |
is_secure() | 通过安全的链接(HTTPS )发送请求时返回True |
host | 请求定义的主机名,如果客户端定义了端口号,还包括端口号 |
path | URL 路径部分 |
query_string | URL 的查询字符串部分,返回原始的二进制值 |
full_path | URL 路径和查询字符串部分 |
url | 客户端请求的完整的URL |
base_url | 同url ,但没有查询字符串部分 |
remote_addr | 客户端的IP 地址 |
environ | 请求的原始WSGI 环境字典 |
2.5.2 请求分派
Flask
为了完成将客户端发来的请求与视图函数相对应,会从应用的URL映射中查找请求的URL。URL映射是URL和视图函数之间的对应关系。
若想查看Flask
中定义的URL映射会是什么样子,可调用应用实例的url_map
属性,如下:
from hello.py import app
app.url_map
2.5.3 请求钩子
有时我们需要在请求之前和请求之后执行相关代码,例如,在请求开始时,可能需要创建数据库连接或者验证发起请求的用户身份。
Flask
提供注册通用函数的功能,注册的函数可在请求被分派到视图函数之前或之后调用,通用注册函数有:
before_request
注册一个函数,在每次请求之前运行
before_first_request
注册一个函数,只在处理第一个请求之前运行。可以通过这个钩子添加服务器初始化任务
after_request
注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行
teardown_request
注册一个函数,即使有未处理的异常抛出,也在每次请求之后运行
在请求钩子函数和视图函数之间共享数据一般会用应用上下文全局变量g
。
2.5.4 响应
Flask
调用视图函数后,会将其返回值作为响应内容。一般情况下,响应及时一个简单的字符串,作为HTML
页面返回给浏览器端。
Flask
响应可包括3个参数,第一个参数是上面提到的响应内容,第二个参数是状态码,默认为200,第三个参数是HTTP
响应头部组成的字符串。
Flask
视图函数还可以返回一个响应对象make_response()
,该函数可接受1、2或3个参数(与视图函数的返回值相对应),即make_response
会返回一个等效的响应对象。
响应对象常用属性和方法如下:
属性或方法 | 描述 |
---|---|
status_code | HTTP 数字状态码 |
headers | 一个类似字典的对象,包含随响应发送的所有首部 |
set_cookie() | 为响应添加一个cookie |
delete_cookie() | 删除一个cookie |
content_length | 响应主体的长度 |
content_type | 响应主题的媒体类型 |
set_data() | 使用字符串或字节值设定响应 |
get_data() | 获取响应主体 |
一些特殊的响应
- 重定向响应
重定向响应没有页面文档,只会告诉浏览器一个URL
,用来加载新页面。该响应对应的状态为302,在Location
首部提供目标URL
。
Flask
中提供了redirect()
辅助函数,用来生成这种响应,如下:
from flask import redirect
@app.rout("/")
def index():
return redirect("http://www.baidu.com")
- 错误响应
Flask
中可用abort
函数生成该响应,如下:
from flask import abort
@app.rout("/usr/<id>")
def get_user(id):
user = load_user(id)
if not user:
abort(404)
return '<h1>hello</h1>'