Flask 请求源码分析
执行app.run()方法:
def run(self, host=None, port=None, debug=None, **options):
from werkzeug.serving import run_simple
if host is None:
host = '127.0.0.1'
if port is None:
server_name = self.config['SERVER_NAME']
if server_name and ':' in server_name:
port = int(server_name.rsplit(':', 1)[1])
else:
port = 5000
if debug is not None:
self.debug = bool(debug)
options.setdefault('use_reloader', self.debug)
options.setdefault('use_debugger', self.debug)
try:
#执行,self=app---->执行Flask类的__call__方法
run_simple(host, port, self, **options)
finally:
self._got_first_request = False
run方法
执行Flask.__call__方法:
#包含请求相关的所有信息
def __call__(self, environ, start_response):
"""Shortcut for :attr:`wsgi_app`."""
return self.wsgi_app(environ, start_response)
执行wsgi_app()方法:
def wsgi_app(self, environ, start_response):
#获取请求数据,并进行封装和加工,
ctx = self.request_context(environ)
#将RequestContext(request,session)封装在Local中
'''
{'唯一标识':{'stack':[RequestContext(request,session),]}
}
'''
ctx.push()
error = None
try:
try:
#调用视图函数
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
执行RequestContext.__init__()和push()方法:
__init__():获取request
def __init__(self, app, environ, request=None):
self.app = app
if request is None:
#实际是一个Request对象,将request信息封装到Request(environ)中,并赋值给RequestContext对象中
request = app.request_class(environ)
self.request = request
self.url_adapter = app.create_url_adapter(self.request)
self.flashes = None
self.session = None
push()方法:将RequestContext对象添加到Local中,获取/创建session
def push(self):
top = _request_ctx_stack.top
if top is not None and top.preserved:
top.pop(top._preserved_exc)
app_ctx = _app_ctx_stack.top
if app_ctx is None or app_ctx.app != self.app:
app_ctx = self.app.app_context()
app_ctx.push()
self._implicit_app_ctx_stack.append(app_ctx)
else:
self._implicit_app_ctx_stack.append(None) if hasattr(sys, 'exc_clear'):
sys.exc_clear()
#将当前requestContext对象放到Local中,
_request_ctx_stack.push(self) # Open the session at the moment that the request context is
# available. This allows a custom open_session method to use the
# request context (e.g. code that access database information
# stored on `g` instead of the appcontext). #赋值操作将self.session=SecureCookieSession()
#SecureCookieSession()实际上是一个字典
self.session = self.app.open_session(self.request)
if self.session is None:
#用户第一次进来session={}执行,返回NullSession
self.session = self.app.make_null_session()
当请求进来时:执行open_session()方法:
class SecureCookieSessionInterface(SessionInterface):
def open_session(self, app, request):
s = self.get_signing_serializer(app)
if s is None:
return None
#去cookie中获取session作为key,所对应的值(包含了当前用户所有的session数据)
val = request.cookies.get(app.session_cookie_name)
#没有
if not val:
#返回SecureCookieSession
return self.session_class()
max_age = total_seconds(app.permanent_session_lifetime)
try:
#val存在的话
#解密 将加密的字符串解密程字典
data = s.loads(val, max_age=max_age)
return self.session_class(data)
except BadSignature:
return self.session_class()
这是我们已经将RequestContext(request,session)的对象放到Local中,并且request和session的初始值也获取到了,
上面方法就是为了执行下面两句:
ctx = self.request_context(environ)
ctx.push() 执行上面的语句后我们在wagi_app()方法中继续向下执行,
触发视图函数
Flask类中
def full_dispatch_request(self):
"""Dispatches the request and on top of that performs request
pre and postprocessing as well as HTTP exception catching and
error handling. .. versionadded:: 0.7
"""
#执行@before_first_request所装饰的所有函数
self.try_trigger_before_first_request_functions()
try:
request_started.send(self)
#执行@before_request装饰的所有函数 看是否有返回值
rv = self.preprocess_request()
if rv is None:
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)
#执行@after_request所装饰的所有函数
return self.finalize_request(rv)
执行finalize_request()方法:
def finalize_request(self, rv, from_error_handler=False):
"""Given the return value from a view function this finalizes
the request by converting it into a response and invoking the
postprocessing functions. This is invoked for both normal
request dispatching as well as error handlers. Because this means that it might be called as a result of a
failure a special safe mode is available which can be enabled
with the `from_error_handler` flag. If enabled, failures in
response processing will be logged and otherwise ignored. :internal:
"""
response = self.make_response(rv)
try:
#执行@after_request所装饰的所有函数
response = self.process_response(response)
request_finished.send(self, response=response)
except Exception:
if not from_error_handler:
raise
self.logger.exception('Request finalizing failed with an '
'error while handling an error')
return response
执行process_response()方法
def process_response(self, response):
"""Can be overridden in order to modify the response object
before it's sent to the WSGI server. By default this will
call all the :meth:`after_request` decorated functions. .. versionchanged:: 0.5
As of Flask 0.5 the functions registered for after request
execution are called in reverse order of registration. :param response: a :attr:`response_class` object.
:return: a new response object or the same, has to be an
instance of :attr:`response_class`.
"""
ctx = _request_ctx_stack.top
bp = ctx.request.blueprint
funcs = ctx._after_request_functions
if bp is not None and bp in self.after_request_funcs:
funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
if None in self.after_request_funcs:
funcs = chain(funcs, reversed(self.after_request_funcs[None]))
for handler in funcs:
response = handler(response)
#保存session
if not self.session_interface.is_null_session(ctx.session):
self.save_session(ctx.session, response)
return response
具体是怎么保存session的呢?
看save_session()方法
session.py中
def save_session(self, app, session, response):
domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app) # Delete case. If there is no session we bail early.
# If the session was modified to be empty we remove the
# whole cookie.
if not session:
if session.modified:
response.delete_cookie(app.session_cookie_name,
domain=domain, path=path)
return # Modification case. There are upsides and downsides to
# emitting a set-cookie header each request. The behavior
# is controlled by the :meth:`should_set_cookie` method
# which performs a quick check to figure out if the cookie
# should be set or not. This is controlled by the
# SESSION_REFRESH_EACH_REQUEST config flag as well as
# the permanent flag on the session itself.
if not self.should_set_cookie(app, session):
return httponly = self.get_cookie_httponly(app)
secure = self.get_cookie_secure(app)
expires = self.get_expiration_time(app, session)
#加密操作
val = self.get_signing_serializer(app).dumps(dict(session))
#将session保存在cookie中
response.set_cookie(app.session_cookie_name, val,
expires=expires, httponly=httponly,
domain=domain, path=path, secure=secure)
globals.py
def _lookup_req_object(name):
# top实际是一个RequestContext对象
'''
{
'唯一标识':{'stack':[RequestContext(request,session),]}
}
'''
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg) #得到session:RequestContext(request,session).session
#得到request:RequestContext(request,session).request
return getattr(top, name) def _lookup_app_object(name):
top = _app_ctx_stack.top
if top is None:
raise RuntimeError(_app_ctx_err_msg)
return getattr(top, name) def _find_app():
top = _app_ctx_stack.top
if top is None:
raise RuntimeError(_app_ctx_err_msg)
return top.app # context locals
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
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'))
Flask 请求源码分析的更多相关文章
- Tomcat处理HTTP请求源码分析(下)
转载:http://www.infoq.com/cn/articles/zh-tomcat-http-request-2 很多开源应用服务器都是集成tomcat作为web container的,而且对 ...
- Tomcat处理HTTP请求源码分析(上)
Tomcat处理HTTP请求源码分析(上) 作者 张华 发布于 2011年12月8日 | 8 讨论 分享到: 微博 微信 Facebook Twitter 有道云笔记 邮件分享 稍后阅读 我的阅读清单 ...
- # Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析#
Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析 Volley源码一共40多个类和接口.除去一些工具类的实现,核心代码只有20多个类.所以相对来说分析起来没有那么吃力.但是要想分析透 ...
- Tomcat处理HTTP请求源码分析(上)(转)
转载自:http://www.infoq.com/cn/articles/zh-tomcat-http-request-1 很多开源应用服务器都是集成tomcat作为web container的,而且 ...
- 知识小罐头07(tomcat8请求源码分析 下)
感觉最近想偷懒了,哎,强迫自己也要写点东西,偷懒可是会上瘾的,嘿嘿!一有写博客的想法要赶紧行动起来,养成良好的习惯. ok,继续上一篇所说的一些东西,上一篇说到Connector包装了那两个对象,最后 ...
- Okhttp同步请求源码分析
进阶android,OKhttp源码分析——同步请求的源码分析 OKhttp是我们经常用到的框架,作为开发者们,我们不单单要学会灵活使用,还要知道他的源码是如何设计的. 今天我们来分析一下OKhttp ...
- 知识小罐头06(tomcat8请求源码分析 中)
更正上一篇一个小错误,Connector中首先是将socket请求过来的信息封装成一个普通的Request对象(上一篇我写成HttpRequest对象,失误失误,根本就木有HttpRequest这样的 ...
- 知识小罐头05(tomcat8请求源码分析 上)
这一篇我们不看源码,就大概理一下Tomcat内部组成部分!前面花费了两篇博客的篇幅来说说了一般的maven web项目并部署到tomcat运行,其实都是为这篇做铺垫的! 其实我下载了tomcat7,t ...
- Flask上下文源码分析(二)
前面第一篇主要记录了Flask框架,从http请求发起,到返回响应,发生在server和app直接的过程. 里面有说到,Flask框架有设计了两种上下文,即应用上下文和请求上下文 官方文档里是说先理解 ...
随机推荐
- 海康威视监控设备的Yv12视频在XNA框架中播放
最近使用海康威视的5寸一体化智能球,查阅些SDK, 在Winform中海康威视能较好的集成,但是对于Yv12编解码和实时视频流的支持未找到较好的SDK介绍. 因为项目需要是用在XNA游戏框架中,本身有 ...
- shell 颜色
PS1='\[\e[33;1m\][\u@\h \W]\\$ \[\e[m\]' echo -e "\033[30m 黑色字oldboy trainning \033[0m" ec ...
- SVN版本库的备份、还原、移植(初级篇、中级篇和高级篇)
版本库数据的移植:svnadmin dump.svnadmin load 导出: $svnlook youngest myrepos //查看到目前为止最新的版本号 $svnadmin dump my ...
- GZipStream
命名空间: System.IO.Compression 说明: 此类表示 GZip 数据格式,它使用无损压缩和解压缩文件的行业标准算法.这种格式包括一个检测数据损坏的循环冗余校验值.GZip 数据格式 ...
- yii2 basic 简洁安装教程
虽然yii官网上说叫咱们用composer安装来安装,但是鄙人感觉这样的安装方式会将自己写的代码共享到github中,因此不太建议大家这样用.下面来给大家介绍basic简洁的安装方法. 第一步,下载b ...
- npm install 不自动生成 package-lock.json文件
package-lock.json这个文件的作用就不详细说明了 有需要的可以参考 :https://www.cnblogs.com/cangqinglang/p/8336754.html 网上都说 n ...
- Oracle 常用性能监控SQL语句
1. --查看表锁 SELECT * FROM SYS.V_$SQLAREA WHERE DISK_READS > 100; 2. --监控事例的等待 SELECT EVEN ...
- Django admin 注册多个app
class game(models.Model): content = models.TextField() def __str__(self): return 'To game %s' % self ...
- JavaScript------字符串中各种方法
参考“菜鸟教程” http://www.runoob.com/js/js-strings.html 1.search() var s = "Hello World"; alert( ...
- STL中的容器
STL中的容器 一. 种类: 标准STL序列容器:vector.string.deque和list. 标准STL关联容器:set.multiset.map和multimap. 非标准序列容器slist ...