【Flask学习笔记:四】Flask 应用和请求上下文

Xandy ·
更新时间:2024-09-20
· 965 次阅读

目录:
  【Flask学习笔记:一】开发环境部署
  【Flask学习笔记:二】Flask 入门基础知识
  【Flask学习笔记:三】Flask 中的 request、response
  【Flask学习笔记:四】Flask 应用和请求上下文

【Flask学习笔记:四】Flask 应用和请求上下文

  Flask 从客户端收到请求时,要让视图函数能访问一些对象,这样才能处理请求。请求对象就是一个很好的例子,它封装了客户端发送的 HTTP 请求。
  要想让视图函数能够访问请求对象,一种直接了当的方式是将其作为参数传入视图函数,不过这会导致应用中的每个视图函数都多出一个参数。除了访问请求对象,如果视图函数在处理请求时还要访问其他对象,情况会变得更糟。
  为了避免大量可有可无的参数把视图函数弄得一团糟, Flask 使用上下文临时把某些对象变为全局可访问。

有了上下文,便可以像下面这样编写视图函数:

from flask import request @app.route('/') def index(): user_agent = request.headers.get('User-Agent') return '

Your browser is {}

'.format(user_agent)

  在这个视图函数中我们把 request 当作全局变量使用。事实上,request 不可能是全局变量。在多线程服务器中,多个线程同时处理不同客户端发送的不同请求时,每个线程看到的 request 对象必然不同。Flask 使用上下文让特定的变量在一个线程中全局可访问,与此同时不会干扰其他线程。

在 Flask 中有两种上下文:应用上下文请求上下文

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

Flask 在发送请求之前推送应用和请求上下文,请求处理完成后再将其删除。应用上下文被推送后,就可以在当前线程中使用 current_app 和 g 变量。类似的,请求上下文被推送后,就可以使用 request 和 session 变量。如果使用这些变量时没有激活应用上下文或请求上下文,就会导致错误。

简单的画一个原理图:
在这里插入图片描述
1.接收到一个请求时,Flask 会先执行 wsgi_app 这个函数对象

def __call__(self, environ, start_response): """Shortcut for :attr:`wsgi_app`.""" return self.wsgi_app(environ, start_response)

2.实例化一个 RequestContext 对象,存储了此次请求的一些信息,

def wsgi_app(self, environ, start_response): ctx = self.request_context(environ) 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)

3.将实例化的 RequestContext 推送到 _request_ctx_stack 中, 在此之前 Flask 会检查 _app_ctx_stack 这个栈顶是否存在 AppContext,不存在则实例化了一个 AppContext 推到 _app_ctx_stack 中,然后才将 RequestContext 推入到 _request_ctx_stack 中

def push(self): top = _request_ctx_stack.top if top is not None and top.preserved: top.pop(top._preserved_exc) # Before we push the request context we have to ensure that there # is an application context. 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() _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()

4.最后将存储的ctx对象pop掉,整个请求结束。

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)
作者:Mr_Zhang2



flask 上下文

需要 登录 后方可回复, 如果你还没有账号请 注册新账号