【Flask学习】1.2Flask的工作方式


上一节我们开发了1个简单的Flask程序,并且知道它的最基本运行逻辑:创建1个程序实例,然后定义1个或多个路由,最后启动web服务器去轮询处理收到的请求。
或许此时你对“ 程序实例收到请求并给予响应的过程”有些疑惑,我也是,下来我们一起探索。

程序和请求上下文

Flask程序实例收到从客户端发来的请求时,要让视图函数能访问一些对象,这样才能更好处理请求。
请求对象,就是1个很好的例子,它封装了客户端发送的HTTP请求。

要让视图函数能够访问请求对象,Flask使用上下文临时把某些对象变成全局可访问(仅单个线程)。有了上下文,就可以这样访问对象:

from flask import Flask, request

app = Flask(__name__)

@app.route('/')
def index():
	"""访问请求对象的请求头"""
	user_agent = request.headers.get('User-Agent')
	return '<h1>Your browser is %s.</h1>' % user_agent

if __name__ == '__main__':
	app.run(debug=True)

在Flask中有两种上下文:程序上下文和请求上下文,一些说明如下:

变量名上下文说明
current_app程序上下文当前激活程序的程序实例
g程序上下文处理请求时用作临时存储的对象,每次请求都会重设这个变量
request请求上下文请求对象,封装了客户端发出的HTTP请求的内容
session请求上下文用户会话,用于存储请求之间需要“记住”的值的字典

Flask在分发请求之前激活(或推送)程序和请求上下文,那么就可以使用上面几个变量了,且请求处理完成后会将它删除。
如果在使用全局变量前没有激活上下文,就会导致错误。下面在python shell会话演示程序上下文的使用方法:

(website) D:\Flask>python
......
>>> from hello import app
>>> from flask import current_app
>>> current_app.name		# 没激活程序上下文之前就使用全局变量current_app,会导致错误
Traceback (most recent call last):
...
RuntimeError: working outside of application context
>>> app_ctx = app.app_context()		# 获得1个程序上下文
>>> app_ctx.push()			# 推送程序上下文
>>> current_app.name
'hello'
>>> app_ctx.pop()		# 删除程序上下文

请求调度

程序收到客户端发来的请求时,要找到能处理该请求的视图函数。要完成这个动作,Flask会在程序的URL映射中查找请求的URL。

URL映射,是URL和视图函数的对应关系。
在Flask中,使用 app.route 修饰器或者非修饰器形式的 app.add_url_rule() 生成映射。

你想看看Flask程序中的URL映射是什么样子?我们可以在python shell会话中用app.url_map查看。

(venv) $ python
>>> from hello import app
>>> app.url_map
Map([<Rule '/' (HEAD, OPTIONS, GET) -> index>,
 <Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
 <Rule '/user/<name>' (HEAD, OPTIONS, GET) -> user>])

/ 和 /user路由在程序中使用 app.route 修饰器定义。/static路由是Flask 添加的特殊路由,用于访问静态文件。
Flask为每个路由都指定了请求方法,这样在收到相同的URL、不同的请求方法,(可能)会使用不同的视图函数处理。在目前的例子中@app.route()都未指定methods值,但是有HEAD/OPTIONS/GET方法,可以看出这些是默认的,Flask提供了很大的便利!

请求钩子

有时我们需要在处理请求之前或者之后执行代码,比如创建数据库连接,这些会很有用。为了避免在每个视图函数使用重复的代码,我们可以用Flask提供的注册通用函数的功能,注册的函数即在处理请求之前或之后调用。
请求钩子使用修饰器实现,Flask支持下面4种钩子:

函数说明
before_first_request在处理第一个请求之前运行
before_request在每次请求之前运行
after_request如果没有未处理的异常抛出,在每次请求之后运行
teardown_request即使有未处理的异常抛出,也在每次请求之后运行

在请求钩子函数和视图函数之间共享数据,一般使用上下文全局变量g。比如,before_request获取已登录用户,并将其保存到g.user,视图函数就可方便地使用已登录用户的数据。
请求钩子使用例子如下:

from flask import Flask, g
from datetime import datetime

app = Flask(__name__)

@app.before_request
def run_before_request():
	"""在每次请求前运行"""
	cur_time = time.strftime('%Y.%m.%d %H:%M:%S', time.localtime())
    log_msg = "Request arrivered at %s, please note." % cur_time
    g.begin_time = cur_time
    print(log_msg)

@app.route('/')
def index():
	return '<h1>Hello, everyone.</h1><h2>Now is at %s.</h2>' % g.get('begin_time', '2000.10.1 9:00:00')

if __name__ == '__main__':
	app.run(debug=True)

请求http://127.0.0.1:5000/后,服务器日志有run_before_request打印的内容,且请求到达的时间g.begin_time也共享到视图函数使用。

响应

大多数情况,响应是1个简单的字符串,像前面的例子。但HTTP协议需要的不仅是响应的字符串,还有1个重要的组成–状态码,Flask默认设为200,代表请求已被成功处理。
如果需要返回不同的状态码,则把状态码数字作为响应的第2个参数。例如:

@app.route('/error')
def bad_request():
	return '<h1>Bad Request.</h1>', 400

返回的函数还可接受第3个参数,这是1个字典结构的响应头部(Header)。如果不想返回由 1 个、2 个或 3 个值组成的元组,Flask 视图函数还可以返回 Response 对象。make_response() 函数可接受 1 个、2 个或 3 个参数(和视图函数的返回值一样),并返回一个 Response 对象。
有时我们需要在视图函数中进行这种转换,然后在响应对象上调用各种方法,进一步设置响应。

from flask import make_response

@app.route('/')
def index():
	response = make_response('<h1>Tomorrow will come!</h1>')
	response.set_cookie('gift', 'flower')
	return response

有1种名为重定向的特殊响应类型,只告诉浏览器一个新地址用来加载新页面。重定向经常使用302状态码表示,指向的地址由location首部提供。
在Flask,提供了redirect()函数生成这种响应:

from flask import redirect

@app.route('/redirect')
def to_redirect():
	return redirect('http://www.funny.com/new')
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值