Flask系列:工作流程

这个系列是学习《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 种钩子:

  1. before_first_request:注册一个函数,在处理第一个请求之前运行。
  2. before_request:注册一个函数,在每次请求之前运行。
  3. after_request:注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行。
  4. 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) # 使用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容