这个系列是学习《Flask Web开发:基于Python的Web应用开发实战》的部分笔记
客户端——web 服务器——WSGI——application
客户端发送 HTTP 请求,web 服务器在一个地址的端口上等待接收,一旦收到,会将请求通过 WSGI 交给 application 处理,application 就是 flask 框架编写的应用,application 对消息处理后,也通过 WSGI 返回 HTTP 响应给 web 服务器,由服务器发送给客户端。
所有 Flask 程序都必须创建一个程序实例,实例是 Flask 类的对象
安装
$ pip install flask
Collecting flask
Collecting itsdangerous>=0.21 (from flask)
Collecting Werkzeug>=0.7 (from flask)
Using cached Werkzeug-0.11.2-py2.py3-none-any.whl
Collecting Jinja2>=2.4 (from flask)
Using cached Jinja2-2.8-py2.py3-none-any.whl
Collecting MarkupSafe (from Jinja2>=2.4->flask)
Installing collected packages: itsdangerous, Werkzeug, MarkupSafe, Jinja2, flask
Successfully installed Jinja2-2.8 MarkupSafe-0.23 Werkzeug-0.11.2 flask-0.10.1 itsdangerous-0.24
创建实例:
run.py
from flask import Flask
app = Flask(__name__)
Flask 函数需要指定一个参数,是程序主模块或包的名字,大多数情况下,__name__
就是需要的值。
Flask 用这个参数决定程序的根目录,以便稍后能够找到相对于程序根目录的资源文件。
web 服务器
常见的有 uWSGI、Nginx、gunicorn 等
flask 集成了一个开发用的web服务器,同一时间只能处理一个请求
使用 flask 集成的服务器
run.py
if __name__ == '__main__':
app.run(debug=True)
debug = True, 调试模式,激活调试器,当一些文件修改保存后,会自动重新加载,而且出错时,能够显示足够的提示信息,具体到运行哪个文件的哪一行产生的错误,错误原因是什么。正因为会提供丰富的后台信息,所以强烈建议不要在生产环境中开启。
运行
$ python run.py
* Running on http://127.0.0.1:5000/
* Restarting with reloader
WSGI
web 服务器和 web 框架 有很多种,并不总是能互相配合工作,那就要想办法在它们之间搭建一个沟通的桥梁,让它们能正常互发消息,于是出现了 WSGI 规范,规定了 web 服务器将客户端的消息发送给 application ,以及 application 将处理后的消息发送给服务器的方法,这个规范在PEP 333中定义。
flask 对消息的处理
上下文
在多线程服务器中,定义了一个线程池,由多个线程同时处理不同客户的不同请求(并发),当收到请求后,会选一个线程进行处理。flask 使用 程序/请求 上下文,临时把某些对象在一个线程中设置为“全局可访”,这样既不会干扰其他线程,又使得所有视图都能够访问这些对象,并处理请求。flask 收到请求后,在将请求交给线程之前,会 激活/推送 上下文,建立环境,上下文的内容来自 web 服务器 通过 WSGI 发给 application 的消息,当请求处理完成后,再删除上下文。
在 Flask 中有两种上下文: 程序上下文 和 请求上下文 全局变量
| 变量名 | 上下文说明 |
|---|---|---|
| current_app | 当前激活程序的程序实例 |
| g | 处理请求时用作临时存储的对象。每次请求都会重置这个变量 |
| request | 请求对象,封装了客户端发出的 HTTP 请求中的内容 |
| session | 用户会话,用于存储请求之间需要“记住”的值的词典 |
路由、视图函数
- URL 映射
创建视图时,会将 URL、HTTP 方法 和特定的视图进行绑定,建立URL 映射
run.py
@app.route('/') # 使用程序实例提供的`app.route`修饰器,把函数与URL绑定
def index():
return '<h1>Hello World!</h1>'
用浏览器访问http://localhost:5000/
查看URL 映射
>>> from run import app
>>> app.url_map
Map([<Rule '/' (HEAD, POST, OPTIONS, GET) -> index>,
<Rule '/user/<username>' (HEAD, OPTIONS, GET) -> main.user>])
>>>
GET、POST 是请求方法,由路由进行处理。Flask 为每个路由都指 定了请求方法,这样不同的请求方法发送到相同的 URL 上时,会使用不同的视图函数进 行处理。HEAD 和 OPTIONS 由 Flask 自动处理。
当线程收到 HTTP 请求后,在URL映射
中寻找相应 URL、HTTP方法 对应的视图,由该视图进行处理,并返回响应给 web 服务器,发送给客户端。
某些 URL 格式,会发现很多地址中都包含可变部分,Flask 支持这种形式的 URL,只需在 route 修饰器中使用特殊的句法即可
- 关键字参数
http://localhost:5000/user/john
@app.route('/user/<name>') # 对 url 中,/user/ 后面的内容进行匹配、截取,赋值给变量 name,默认匹配字符串,可以指定类型。例如,/user/<int:id> 只匹配 id 为整数的 URL
def user(name): # 变量 name 作为参数传递给函数 user
print name
- 额外参数
作为 查询字符串(url 中问号后面的),这个参数可从 request.args 字典中读取
http://127.0.0.1:5000/index?page=2
@app.route('/index')
def index():
page = request.args.get('page', 1, type=int)
print request.args
ImmutableMultiDict([('page', u'2')])
page=request.args.get('page', 1, type=int)
从 url 获取 键为 page 的 值转换为整形,如果没有 或 转换失败,默认为 1
钩子
在将请求交给视图处理前,或将视图处理的结果返回给 web 服务器前,可以调用钩子,对 请求/响应 进行处理。例如,对于一个用户的请求,检查这个用户的账号有没有通过邮箱确认,如果没有,对某些页面的访问会被禁止访问,重定向到一个特定的页面,而其他页面正常访问。
请求钩子使用修饰器实现。Flask 支持以下 4 种钩子:
- before_first_request:注册一个函数,在处理第一个请求之前运行。
- before_request:注册一个函数,在每次请求之前运行。
- after_request:注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行。
- teardown_request:注册一个函数,即使有未处理的异常抛出,也在每次请求之后运行。
响应
Flask 调用视图函数后,会将其返回值作为响应的内容。大多数情况下,响应就是一个简单的字符串,作为 HTML 页面(也就是 HTTP 的 body)回送客户端。
- 元组
但 HTTP 协议需要的不仅是作为请求响应的字符串。HTTP 响应中一个很重要的部分是状态码
,Flask 默认设为 200,这个代码表明请求已经被成功处理。如果视图函数返回的响应需要使用不同的状态码,那么可以把数字代码
作为第二个返回值,添加到响应文本之后。
@app.route('/')
def index():
return '<h1>Bad Request</h1>', 400
视图函数返回的响应还可接受第三个参数,这是一个由首部(header)组成的字典
,可以 添加到 HTTP 响应中。
- Response 对象
如果不想返回由 1 个、2 个或 3 个值组成的元组,Flask 视图函数还可以使用 make_response() 产生并直接返回完整的Response 对象
。make_response() 函数可以接受 1 个、2 个或 3 个参数(和视图函数的返回值一样),并返回一个Response 对象
。有时我们需要在视图函数中产生Response 对象
,然后在Response 对象
上调用各种方法,进一步 设置响应 。
from flask import make_response
@app.route('/')
def index():
response = make_response('<h1>This document carries a cookie!</h1>')
response.set_cookie('answer', '42') # 设置 cookie
return response
- 重定向
有一种名为重定向
的特殊响应类型。这种响应没有页面文档, 只是用于告诉浏览器一个新地址,以便加载新页面。重定向经常在 Web 表单中使用。
重定向经常使用 302 状态码表示,指向的地址由 HTTP 的Location 首部
提供。重定向响应可以使用 3 个值形式的返回值生成,也可在 Response 对象中设定。不过,由于使用频繁,Flask 提供了redirect() 辅助函数
, 用于生成这种响应。
from flask import redirect
@app.route('/')
def index():
return redirect('http://www.example.com')
- 异常跳出
还有一种特殊的响应由abort 函数
生成,用于处理错误。
from flask import abort
@app.route('/user/<id>')
def get_user(id):
user = load_user(id)
if not user: # 如果用户不存在
abort(404) # 抛出异常
return '<h1>Hello, %s</h1>' % user.name
注意,abort 会直接跳出调用它的函数,抛出异常,把控制权交给 Web 服务器。
flask 的组件
被设计为可扩展形式,只自带两个核心组件:
- werkzeug,负责处理 路由、调试、WSGI
- jinja2,模板引擎,负责对模板进行渲染
其他组件需要单独安装、初始化
扩展的来源:
- 社区开发
- py 标准库/包
- 自行开发
使用:
pip install flask-mail
# pip 安装
from flask.ext.mail import Mail
# 导入, 专为 Flask 开发的扩展,都在 flask.ext 命名空间下, virtualenv 环境中,目录为lib/python2.7/site-packages/
mail = Mail(app)
# 初始化,将 程序实例(app) 作为参数传给 扩展的构造函数,进行初始化。通常在创建程序实例时进行。
mail.send(msg)
# 使用