2.1 初始化
所有Flask应用都必须创建一个应用实例。
Web服务器使用一种名为Web服务器网关接口(WSGI, Web server gateway interface,读作“wiz-ghee”)的协议,把接收自客户端的所有请求都转交给这个对象处理。
应用实例是Flask类的对象,由下面代码创建
from flask import Flask
app = Flask(__name__) #Flask为一个类
Flask类的构造函数只有一个必须指定的参数,即应用主模块或者包的名称。大多数情况下,Python的__name__变量就是所需的值。Flask使用__name__来确定应用的位置,进而找到应用中其他文件的位置,如图像和模板
2.2 路由和视图函数
客户端(例如Web浏览器)把请求发送给Web服务器,Web服务器再把请求发送给Flask应用实例。应用实例需要知道对每个url的请求运行那些代码,所以保存了url到Python函数的映射关系。处理URL和函数之间关系的程序被称为路由
@app.route('/') # 使用app.route装饰器来定义路由
def index(): # 把index()函数注册为应用根地址的处理程序
return '<h1>Hello World!</h1>'
def index(): # 将index函数注册为应用根地址的处理程序
return'<h1>Hello World!</h1>'
app.add_url_rule('/','index',index) # app.add_url_rule()接收3个参数:URL,端点名,视图函数
index()这样处理入站请求的函数称为视图函数。如果应用部署在域名为www.bilibili.com的 服务器上,在浏览器中访问http://www.bilibili.com 后,会触发服务器执行index()函数。这个函数的返回值称为响应,是客户端收到的内容。如果客户端是Web浏览器,响应就是显示给用户查看的文档。视图函数返回的响应可以是包含HTML的简单字符串。
@app.route('/user/<name>') # 定义的路由有一部分是可变的
def user(name):
return '<h1>Hello,{}!</h1>'.format(name) # 路由URL在{}的内容就是动态部分
调用视图函数时,Flask会将动态部分作为参数传入参数。name参数用于生成个性化的欢迎信息。
路由中的动态部分默认是字符串,也可为其他。如路由/user/int:id只会匹配动态片段id为整数的URL,如/user/123。Flask支持路由中使用string, int, float和path类型(path为一种特殊的字符串,特殊之处在于可以包含正斜线)
装饰器是Python语言的标准特性。惯常用法是把函数注册为时间处理程序,在特定事件发生时使用
2.4 Web开发服务器
Flask应用自带Web开发服务器,通过flask run命令启动。这个命令在FLASK_APP环境变量指定的Python脚本中寻找应用实例
Flask提供的Web服务器只适用于开发和测试。
Flask Web开发服务器也可以通过编程的方式启动:调用app.run()方法
2.5 动态路由
添加一个动态路由。在浏览器中访问中国动态URL,会看到一条个性化的信息
hello.py: 包含动态路由的Flask应用
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
@app.route('/user/<name>')
def user(name):
return '<h1>Hello,{}!</h1>'.format(name)
2.6 调试模式
Flask应用可以在调试模式中运行,在此模式下,开发服务器默认会加载两个工具:重载器和调试器。
启用重载器后,Flask会监视项目中的所有源码文件,发现变动时自动重启服务器。在开发过程中运行启动重载器的服务器特别方便,因为每次修改并且保存源码文件以后,服务器都会自动重启,让改动生效
调试器是一个基于Web的工具,当应用抛出未处理的异常时,它会出现在浏览器中。此时,Web浏览器变成一个交互式栈跟踪,可以在里面审查源码,在调用栈的任何位置计算表达式
调试模式默认禁用,在执行flask run之前设定FLASK_DEBUG=1可以启用调试器
2.7 命令行选项
flask --help或者flask可以查看那些选项可以使用
flask shell 在应用上下文打开一个Python shell会话,在会话中可以运行维护任务或者测试,也可以调试问题
flask run 在Web开发服务器中运行应用
flask run --host 告诉服务器在那个网络接口上监听客户端发来的连接
Flask的Web服务器在监听localhost上的连接,因此服务器只接受运行服务器的计算机发送的连接
flask run --host 0.0.0.0 让Web服务器监听公共网络接口上的连接
2.8 请求-响应循环
2.8.1 请求和应用上下文
flask从客户端收到请求时,要让视图函数能访问一些对象,才能处理请求。请求对象封装了客户端发送的http请求
为了避免大量参数把视图函数搞得一团糟,Flask使用上下文临时把某些对象变为全局可访问。有上下文可以这样编写视图函数:
from flask import Flask
@app.route('/')
def index():
user_agent = request.headers.get('User-Agent')
return '<p>Your browser is {}</p>'.format(user_agent)
此视图函数中,request为全局变量(事实上,不可能是全局变量,在多线程服务器中,多个线程同时处理不同客户端发送的不同请求时,每个线程看到的request对象必然不同。Flask使用上下文让特定的变量在一个线程中全局可访问,与此同时却不会干扰其他线程)
flask在分配请求之前激活(或推送)应用和请求上下文,请求处理完成后再将其删除。应用上下文被推送后,就可以在当前线程中使用current_app和g变量。
请求上下文被推送后,就可以使用request和session变量。如果变量未激活应用上下文或请求上下文,就会错误。
运行
from hello import app
from flask import current_app
current_app.name # 未激活应用上下文调用会失败
输出
Traceback (most recent call last):
...
–
运行
app_ctx = app.app_context() # 获取上下文,推送完上下文就可以调用
app_ctx.push()
current_app.name
输出
'hello'
–
运行
app_ctx.pop()
2.8.2 请求分配
应用收到客户端发来的请求时,要找到处理该请求的视图函数,flask会在应用的url映射中查找请求的url。url映射是url与视图函数之间的对应关系。flask应用app.route装饰器或者app.add_url_rule()方法构建映射
from hello import app
app.url_map # 查看flask应用中的url映射
Map([<Rule '/' (OPTIONS, GET, HEAD) -> index>,
<Rule '/static/<filename>' (OPTIONS, GET, HEAD) -> static>,
<Rule '/user/<name>' (OPTIONS, GET, HEAD) -> user>])
/和/user/路由在应用中使用app.route定义
/static/是flask添加的特殊路由,用于访问静态文件
url映射中的(HEAD,OPTIONS,GET)是请求方法,由路由进行处理
flask为每个路由都指定了请求方法,所以即使不同的请求方法发送到相同的url上时,也会使用不同的视图函数处理。HEAD和OPTIONS由flask处理。
可以这样说,在此应用中,url映射中的3个路由都使用GET方法(表示客户端想请求一个如网页的消息)
2.8.3 请求对象
flask通过上下文变量request对外开放请求对象,此对象包含客户端发送的HTTP请求的全部信息。
flask常用的属性与方法
2.8.4 请求钩子
为了避免在每个视图函数中都重复编写代码,Flask提供了注册通用函数功能,注册的函数可以在请求被分配到视图函数之前或之后调用。
请求钩子通过装饰器实现。
flask支持以下四种钩子:
- before_request
注册一个函数,在每次请求之前运行 - before_first_request
注册一个函数,只在处理第一个请求之前运行。可以添加服务器初始化任务 - after_request
注册函数,若未出现未处理的异常,则在每次请求之后运行 - teardown_request
注册函数,即使有未处理的异常抛出,也在每次请求之后运行
在请求钩子函数和视图函数之间共享数据一般使用上下文全局变量g
2.8.5 响应
flask调用视图函数后,会将其返回值作为响应的内容。多数情况下,响应就是一个简单的字符串,作为html页面回送客户端。
但是HTTP协议需要的不仅仅是请求响应的字符串,HTTP中很重要的是状态码,flask默认为200,表明请求已被成功处理
如果视图函数返回的响应需要使用不同的状态码,可以把数字代码作为第二个返回值,添加到响应文本之后。
make_response()可以接受1、2、或3个参数(和视图函数的返回值一样),然后返回一个等效的响应对象。有时需要在视图函数中生成响应对象,然后在响应对象上调用各个方法,进一步设置响应
重定向响应没有页面文档,只会告诉浏览器一个新的url,用以加载新页面。
重定向的状态码通常是302,在location首部中提供目标url,重定向响应可以使用3个值形式的返回值生成,也可以在响应对象中设定。
flask提供的redirect()函数可以生成重定向响应:
from flask import redirect
@app.route('/')
def index():
return redirect('http://www.bilibili.com')
abort()函数用于处理错误
from flask import abort
@app.route('/user/<id>')
def get_user(id):
user = load_user(id)
if not user:
abort(404) # 若url中动态参数id对应的用户不存在,则返回状态码404,abort()不会把控制权交给调用函数,而是抛出异常
return '<h1>Hello,{}</h1>'.format(user.name)