![Flask请求处理流程(request)[待续] Flask请求处理流程(request)[待续]](https://image.shishitao.com:8440/aHR0cHM6Ly9ia3FzaW1nLmlrYWZhbi5jb20vdXBsb2FkL2NoYXRncHQtcy5wbmc%2FIQ%3D%3D.png?!?w=700&webp=1)
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__)
关于上下文,线程协程的相关文章之前整理的如下: