Flask请求处理流程(request)[待续]
WSGI简介
WSGI(全称Web Server Gateway Interface),是为 Python 语言定义的Web服务器和Web应用程序之间的一种简单而通用的接口,它封装了接受HTTP请求、解析HTTP请求、发送HTTP,响应等等的这些底层的代码和操作,使开发者可以高效的编写Web应用。
Flask的WSGI工具箱采用Werkzeug。工作原理如下:
from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple
@Request.application
def hello(request):
return Response('Hello World!')
if __name__ == '__main__':
run_simple('localhost', 4000, hello)

一个最简单的Flask的Hello World示例:
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def index():
if request.method == 'POST':
return 'Hello World!'
if __name__ == '__main__':
app.run()
启动先执行: app.run()
class Flask(_PackageBoundObject):
def run(self, host=None, port=None, debug=None, **options):
from werkzeug.serving import run_simple
try:
# run_simple 是werkzeug 提供的方法,会执行第三个参数 self()
run_simple(host, port, self, **options)
执行app(),对象()表示调用对象的__call__方法
class Flask(_PackageBoundObject):
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
又调用了app.wsgi_app方法
def wsgi_app(self, environ, start_response):
# 1.
ctx = self.request_context(environ)
# 2
ctx.push()
error = None
try:
# 3
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:
# 4.
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
第1步:执行app.request_context方法,把请求的相关信息传进去了
class Flask(_PackageBoundObject):
def request_context(self, environ):
return RequestContext(self, environ)
返回了一个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
request_class = Request ,class Request(BaseRequest...)
class BaseRequest(object):
def __init__(self, environ, populate_request=True, shallow=False):
self.environ = environ
在RequestContext的__init__()方法中,app又调用了request_class方法,也就是Request 实例一个对象,Request又继承了RequestBase而,也就是在这里封装了请求进来的所有数据environ等。
第2步:执行ctx.push()方法
因为ctx是RequestContext类的对象,那我们就要去RequestContext类中找push方法
class RequestContext(object):
def push(self):
# 2.1
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()
# 2.2
_request_ctx_stack.push(self)
self.session = self.app.open_session(self.request)
if self.session is None:
self.session = self.app.make_null_session()
2.1步,其中:_request_ctx_stack = LocalStack() ,_request_ctx_stack是LocalStack类的实例化对象,是一个全局对象。这一步,到_app_ctx_stack这个栈中取最后一个数据,没有就返回None
class LocalStack(object):
def __init__(self):
self._local = Local()
@property
def top(self):
try:
return self._local.stack[-1]
except (AttributeError, IndexError):
return None
2.2步,_request_ctx_stack.push(self)将封装了请求数据的LocalStack的对象封装到列表中。
class LocalStack(object):
def __init__(self):
self._local = Local()
def push(self, obj):
"""Pushes a new item to the stack"""
rv = getattr(self._local, 'stack', None)
if rv is None:
self._local.stack = rv = []
rv.append(obj)
return rv
第3步:app.full_dispatch_request() 执行视图函数 时执行。此处后面再谈论,先进行下一步
第4步,执行了RequestContext 的 pop 方法
class RequestContext(object):
def auto_pop(self, exc):
else:
self.pop(exc)
pop
class RequestContext(object):
def pop(self, exc=_sentinel):
app_ctx = self._implicit_app_ctx_stack.pop()
try:
clear_request = False
if not self._implicit_app_ctx_stack:
self.preserved = False
self._preserved_exc = None
if exc is _sentinel:
exc = sys.exc_info()[1]
self.app.do_teardown_request(exc)
if hasattr(sys, 'exc_clear'):
sys.exc_clear()
request_close = getattr(self.request, 'close', None)
if request_close is not None:
request_close()
clear_request = True
finally:
rv = _request_ctx_stack.pop()
if clear_request:
rv.request.environ['werkzeug.request'] = None
if app_ctx is not None:
app_ctx.pop(exc)
assert rv is self, 'Popped wrong request context. ' \
'(%r instead of %r)' % (rv, self)
实则执行的是LocalStack对象的pop方法移除索引为-1的元素:
class LocalStack(object):
def __init__(self):
self._local = Local()
def pop(self):
stack = getattr(self._local, 'stack', None)
if stack is None:
return None
elif len(stack) == 1:
release_local(self._local)
return stack[-1]
else:
return stack.pop()
第3步,我们在试图函数中使用request的时候,发先request是一个全局变量。
request = LocalProxy(partial(_lookup_req_object, 'request'))
其中LocalProxy的参数是一个偏函数,request作为参数,传入_lookup_req_object函数中。通过上下文管理器的原理,为每个线程创建独有的空间,进行request的封装。根据视图函数中的请求方式或者请求内容执行对应的方法,如在函数中print(request)将出发LocalProxy类对象的__str__()方法:
__str__ = lambda x: str(x._get_current_object())
其中name就是request
@implements_bool
class LocalProxy(object):
__slots__ = ('__local', '__dict__', '__name__', '__wrapped__')
def __init__(self, local, name=None):
object.__setattr__(self, '_LocalProxy__local', local)
object.__setattr__(self, '__name__', name)
if callable(local) and not hasattr(local, '__release_local__'):
object.__setattr__(self, '__wrapped__', local)
def _get_current_object(self):
if not hasattr(self.__local, '__release_local__'):
return self.__local()
try:
return getattr(self.__local, self.__name__)
except AttributeError:
raise RuntimeError('no object bound to %s' % self.__name__)
关于上下文,线程协程的相关文章之前整理的如下:
Flask请求处理流程(request)[待续]的更多相关文章
- Flask - 请求处理流程和上下文源码分析
目录 Flask - 请求处理流程和上下文 WSGI Flask的上下文对象及源码解析 0. 请求入口 1.请求上下文对象的创建 2. 将请求上下文和应用上下文入栈 3.根据请求的URl执行响应的视图 ...
- 笔记-flask-原理及请求处理流程
笔记-flask-原理及请求处理流程 1. 服务器声明及运行 最基本的flask项目代码如下 from flask import Flask app = Flask(__name__) @a ...
- Yii源码阅读笔记(二十一)——请求处理流程
Yii2请求处理流程: 首先:项目路径/web/index.php (new yii\web\Application($config))->run();//根据配置文件创建App实例,先实例化y ...
- Asp.Net构架(Http请求处理流程)、(Http Handler 介绍)、(HttpModule 介绍)
Asp.Net构架(Http请求处理流程) Http请求处理流程概述 对于普通访问者来说,这就像每天太阳东边升起西边落下一样是理所当然的:对于很多程序员来说,认为这个与己无关,不过是系统管理员或者网管 ...
- Http请求处理流程
本文结构: 一.HTTP请求处理流程的基础 1.网络分层 因特网TCP/IP分层模型共有五层:应用层.传输层.网络层.网络接口层和物理层.这种分层模型不同于OSI七层参考模型,但是,是实际使用中采用的 ...
- springmvc源码分析系列-请求处理流程
接上一篇-springmvc源码分析开头片 上一节主要说了一下springmvc与struts2的作为MVC中的C(controller)控制层的一些区别及两者在作为控制层方面的一些优缺点.今天就结合 ...
- 走进JavaWeb技术世界8:浅析Tomcat9请求处理流程与启动部署过程
谈谈 Tomcat 请求处理流程 转自:https://github.com/c-rainstorm/blog/blob/tomcat-request-process/reading-notes &l ...
- Webflux请求处理流程
spring mvc处理流程 在了解SpringMvc的请求流程源码之后,理解WebFlux就容易的多,毕竟WebFlux处理流程是模仿Servlet另起炉灶的. 下面是spring mvc的请求处理 ...
- 04-SpringMVC之请求处理流程
SpringMVC之请求处理流程 我们知道DispatcherServlet就是一个HttpServlet,而HttpServlet的请求就从doGet/doPost开始 DispatcherServ ...
随机推荐
- Python简单网页爬虫——极客学院视频自动下载
http://blog.csdn.net/supercooly/article/details/51003921
- html frameset的介绍
frameset 元素可以定义一个框架集.它被用来组织多个窗口(框架).每个框架存有独立的文档. 属性 ①border 设置框架的边框粗细. ②bordercolor 设置框架的边框颜色. ③fram ...
- Android开发——1轻松战胜开发环境
写在前头的话:鄙人乃2016年本科毕业的程序yuan一枚,大学阶段从未学过安卓,java也是一知半解,回想这一年半的开发生涯真的是相当悲壮.你要是问我喜欢开发吗,当然确定一定以及肯定地告诉你不喜欢啊! ...
- asp.net文件压缩,下载,物理路径,相对路径,删除文件
知识动手实践一次,就可以变成自己的了.不然一直是老师的,书本的. 这几天做了一个小小的项目,需要用到文件下载功能,期初想到只是单个的文件,后面想到如果很多文件怎么办?于是又想到文件压缩.几经波折实践, ...
- zabbix的深入了解
一,Zabbix Web操作深入 1.1 Zabbix Web下的主机和模版以及监控项的添加方式 (1)创建一个模版 我们所有的功能几乎都是在模版中定义的 我们再点进新创建的模版查看 模版里几乎可以设 ...
- Java——线程同步
body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...
- >CH07-cubemap
使用rendermonkey进行一个天空球的贴图,内容来自<<shaders for gpa>> 不知道是不是用的182版RM的原因,照着书上做一个天空球的CUBEMAP,老不 ...
- 给迷茫的你学习Node.js最好的方法
这是真事儿,在3w咖啡整理书稿,然后小弟梁过来了,聊聊他的现状,一副很不好的样子,在天津我曾带过他大半年,总不能不管,我给他的建议是:“每天看10个npm模块” 对于学习Node.js迷茫的人来说,这 ...
- Linux内核参数优化记录
//fs.file-max 最大打开文件数 //fs.nr_open=20480000 单个进程允许打开的文件句柄上限 //信号量及共享内存,可以使用ipcs -l来获取 //kernel.sem 信 ...
- 12个有趣的 XSS Vector
XSS Vector #1 <script src=/〱20.rs></script> URL中第二个斜杠在Internet Explorer下(测试于IE11)可被U+303 ...