flask请求和应用上下文
关于WSGI
WSGI(全称Web Server Gateway Interface),是为 Python 语言定义的Web服务器和Web应用程序之间的一种简单而通用的接口,它封装了接受HTTP请求、解析HTTP请求、发送HTTP,响应等等的这些底层的代码和操作,使开发者可以高效的编写Web应用。
一个简单的使用WSGI的App例子:
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'<h1>Hello, I Am WSGI!</h1>']
environ: 一个包含全部HTTP请求信息的字典,由WSGI Server解包HTTP请求生成。start_response: 一个WSGI Server提供的函数,调用可以发送响应的状态码和HTTP报文头, 函数在返回前必须调用一次start_response()。application()应当返回一个可以迭代的对象(HTTP正文)。application()函数由WSGI Server直接调用和提供参数。- Python内置了一个
WSGIREF的WSGI Server,不过性能不是很好,一般只用在开发环境。可以选择其他的如Gunicorn。

Flask的上下文对象
Flask有两种Context(上下文),分别是
RequestContext请求上下文Request请求的对象,封装了Http请求(environ)的内容Session根据请求中的cookie,重新载入该访问者相关的会话信息。AppContext程序上下文g处理请求时用作临时存储的对象。每次请求都会重设这个变量current_app当前激活程序的程序实例
生命周期:
current_app的生命周期最长,只要当前程序实例还在运行,都不会失效。Request和g的生命周期为一次请求期间,当请求处理完成后,生命周期也就完结了Session就是传统意义上的session了。只要它还未失效(用户未关闭浏览器、没有超过设定的失效时间),那么不同的请求会共用同样的session。
Flask处理流程

第一步:创建上下文
Flask根据WSGI Server封装的请求等的信息(environ)新建RequestContext对象 和AppContext对象
# 声明对象
# LocalStack LocalProxy 都由Werkzeug提供
# 我们不深究他的细节,那又是另外一个故事了,我们只需知道他的作用就行了
# LocalStack 是栈结构,可以将对象推入、弹出
# 也可以快速拿到栈顶对象。当然,所有的修改都只在本线程可见。
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
# 如果调用一个LocalStack实例, 能返回一个 LocalProxy 对象
# 这个对象始终指向 这个LocalStack实例的栈顶元素。
# 如果栈顶元素不存在,访问这个 LocalProxy 的时候会抛出 RuntimeError异常
# LocalProxy对象你只需暂时理解为栈里面的元素即可了
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))
# RequestContext
class RequestContext(object):
def __init__(self, app, environ, request=None):
self.app = app
if request is None:
request = app.request_class(environ)
self.request = request
self.url_adapter = app.create_url_adapter(self.request)
self.flashes = None
self.session = None
#AppContext
class AppContext(object):
def __init__(self, app):
self.app = app
self.url_adapter = app.create_url_adapter(None)
self.g = app.app_ctx_globals_class()
self._refcnt = 0
这里需要注意的是,RequestContext在初始化的时候,当前Flask的实例作为参数被传进来。虽然每次的请求处理都会创建一个RequestContext对象,但是每一次传入的app参数却是同一个。通过这个机制,可以使得:
由同一个Flask实例所创建的
RequestContext,其成员变量app都是同一个Flask实例对象 。实现了多个RequestContext对应同一个current_app的目的。
第二步:入栈
将RequestContext对象push进_request_ctx_stack里面。在这次请求期间,访问request对象,session对象将指向这个栈的栈顶元素
class RequestContext(object):
def push(self):
....
_app_ctx_stack.push(self)
appcontext_pushed.send(self.app)
AppContext对象push进_app_ctx_stack里面。在这次请求期间,访问g对象将指向这个栈的栈顶元素
class AppContext(object):
def push(self):
....
_request_ctx_stack.push(self)
第三步:请求分发
response = self.full_dispatch_request()
Flask将调用full_dispatch_request函数进行请求的分发,之所以不用给参数,是因为我们可以通过request对象获得这次请求的信息。full_dispatch_request将根据请求的url找到对应的蓝本里面的视图函数,并生成一个response对象。注意的是,在请求之外的时间,访问request对象是无效的,因为request对象依赖请求期间的_request_ctx_stack栈。
第四步:上下文对象出栈
这次HTTP的响应已经生成了,就不需要两个上下文对象了。分别将两个上下文对象出栈,为下一次的HTTP请求做出准备。
第五步:响应WSGI
调用Response对象,向WSGI Server返回其结果作为HTTP正文。Response对象是一个 可调用对象,当调用发生时,将首先执行WSGI服务器传入的start_response()函数 发送状态码和HTTP报文头。
最后附上Flask处理请求的wsgi_app函数
# environ: WSGI Server封装的HTTP请求信息
# start_response: WSGI Server提供的函数,调用可以发送状态码和HTTP报文头
def wsgi_app(self, environ, start_response):
# 根据environ创建上下文
ctx = self.request_context(environ)
# 把当前的request context,app context绑定到当前的context
ctx.push()
error = None
try:
try:
#根据请求的URL,分发请求,经过视图函数处理后返回响应对象
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.make_response(self.handle_exception(e))
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
# 最后出栈
ctx.auto_pop(error)
flask请求和应用上下文的更多相关文章
- Flask请求和应用上下文源码分析
flask的request和session设置方式比较新颖,如果没有这种方式,那么就只能通过参数的传递. flask是如何做的呢? 1:本地线程,保证即使是多个线程,自己的值也是互相隔离 1 im ...
- 02 flask 请求钩子、异常捕获、上下文、Flask-Script 扩展、jinja2 模板引擎、csrf防范
一 请求勾子 在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如: 在请求开始时,建立数据库连接: 在请求开始时,根据需求进行权限校验: 在请求结束时,指定数据的交互格式: 为了让每个 ...
- Flask(4)- flask请求上下文源码解读、http聊天室单聊/群聊(基于gevent-websocket)
一.flask请求上下文源码解读 通过上篇源码分析,我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(en ...
- flask 请求上下文源码(转)
本篇阅读目录 一.flask请求上下文源码解读 二.http聊天室(单聊/群聊)- 基于gevent-websocket 回到顶部 转:https://www.cnblogs.com/li-li/p/ ...
- Flask的请求钩子与上下文简览
请求钩子(Hook) 在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如:在请求开始时,建立数据库连接:在请求结束时,指定数据的交互格式.为了让>每个视图函数避免编写重复功能的代 ...
- flask请求钩子、HTTP响应、响应报文、重定向、手动返回错误码、修改MIME类型、jsonify()方法
请求钩子: 当我们需要对请求进行预处理和后处理时,就可以用Flask提供的回调函数(钩子),他们可用来注册在请求处理的不同阶段执行的处理函数.这些请求钩子使用装饰器实现,通过程序实例app调用,以 b ...
- flask请求访问数据
flask请求访问数据 在flask框架中,访问请求数据由全局的request对象来提供,在flask框架中,request对象具有 全局作用域: from flask import request ...
- flask请求上下文
先看一个例子: #!/usr/bin/env python # -*- coding:utf-8 -*- import threading # local_values = threading.loc ...
- flask 请求上下文
一篇引用大牛的 https://www.cnblogs.com/zhaopanpan/p/9457343.html ### 线程安全 ```python# 线程不安全class Foo(object) ...
随机推荐
- 进一步优化SPA的首屏打开速度(模块化与懒载入) by 嗡
前言 单页应用的优点在于一次载入全部页面资源,利用本地计算能力渲染页面.提高页面切换速度与用户体验.但缺点在于全部页面资源将被一次性下载完,此时封装出来的静态资源包体积较大,使得第一次打开SPA页面时 ...
- Linux tar This does not look like a tar archive
由于昨天公司内网服务器坏了,所以急需搭建新的Linux环境. 在安装maven时,使用tar 命令解压maven.tar.gz出现: tar :This does not look like a ta ...
- Thinkphp3.2 PHPMailer 发送 QQ邮箱 163邮箱
在进入正题这前先看下网易(163)邮箱的服务器地址和端口号 类型 服务器名称 服务器地址 SSL协议端口号 非SSL协议端口号 收件服务器 POP pop.163.com 995 110 收件服务器 ...
- ci 框架插入时返回插入的id号
$this->db->insert('goods',$data); $gid=$this->db->insert_id('goods'); return $gid;
- javascript 实现java中的Map
javascript实现java中的Map,代码是在国外的一个网站上看到的(http://stackoverflow.com/questions/368280/javascript-hashmap-e ...
- addLoadEvent
function addLoadEvent(func){ var oldOnload = window.onload; if(typeof(window.onload) != 'function'){ ...
- SQL里3个表的连接查询
两种:1.select * from 表1,表2,表3 where 表1.字段=表2.字段 and 表1.字段=表3.字段这种效率比较低 结构简单数据量小可以采用2.select * from 表1 ...
- Dirichlet Distribution
Beta分布: 二项式分布(Binomial distribution): 多项式分布: Beta分布: Beta分布是二项式分布的共轭先验(conjugate prior) Dirichlet Di ...
- Mybatis实现了接口绑定,使用更加方便。
1.Mybatis实现了接口绑定,使用更加方便. 在ibatis2.x中我们需要在DAO的实现类中指定具体对应哪个xml映射文件, 而Mybatis实现了DAO接口与xml映射文件的绑定,自动为我们生 ...
- 从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射
从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射.Collection 接口又有 3 ...