Flask 框架理解(一)

web 服务器 , web 框架 以及 WSGI

这里说的 web 服务器特指纯粹的 python HTTP 服务器(比如 Gunicorn,而不是 Apache,Nginx这些)

一般来说, web 服务器负责建立并管理监听套接字,并且解析所有收到的 HTTP 请求。Web 框架负责 URL 分发,根据 HTTP 中请求路径生成响应。 而 WSGI(pep 333) 则是 web 服务器调用 web 框架的一个调用惯例。用来解偶 web 服务器和 web 框架。

通过 flask 的源码能比较清晰的看到这三者关系

    def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
error = None
try:
try:
ctx.push()
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) def __call__(self, environ, start_response):
"""The WSGI server calls the Flask application object as the
WSGI application. This calls :meth:`wsgi_app` which can be
wrapped to applying middleware."""
return self.wsgi_app(environ, start_response)

从这里可以看出, flask 的 application 是一个 WSGI 可调用对象。如果去看 Flask Appication 的 run 方法, 就能发现最终是启动一个 Werkzeug serving.py 中的一个 基于BaseHTTPServer.HTTPServer 实现的 WSGIServer,也就是 web 服务器。证实 web 服务器通过 WSGI 接口调用 web 框架作出响应。这里也能很清楚的看到 web 框架的基础功能就是分发请求,作出响应。

理解全局变量

在 flask 中有 4 个方便好用的全局变量 current_app, request, session, g。严格意义上来说是线程级别的全局变量(具体可看 Werkzeug 的 LocalStack 源码),也就是只有当前线程能访问。正因为用的多, 更应该花点时间去理解这几个变量的含义以及生命周期。

# 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'))

对于请求-响应模式, 响应需要根据具体的请求来做出合理的响应。 这四个全局变量就是用来提供请求的具体信息,即请求上下文。从上面 wsgi_app 函数中也可以看出,有请求过来, 调用 wsig_app 时, 会构建一个当前请求的上下文实例(RequestContext),将 http 请求原始信息存到 request 属性, 并将其 push 到当前线程的全局栈 _request_ctx_stack。接着将当前 flask 实例 push 到 _app_ctx_stack, 存储到上下文实例的 app 属性中。最后解析请求中的 cookie, 构建 Session 实例存到上下文实例的 session 属性中。 这样每个请求的上下文中就携带了, http 请求的原始信息, 当前 flask 实例上下文信息, 以及 cookie 提取的 session 信息。 一个请求所需要的信息基本就全部包含了。至于 g 只是当前 flask 实例上下文对象的一个属性。在响应构造完成后, 会把当前上下文 session 信息存到 cookie,所以裸 flask 框架的 session 全部信息是存在客户端的 cookie 里面。接着弹出当前请求的上下文, 弹出当前请求的 flask 实例上下文。

def push(self):
"""Binds the request context to the current context."""
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) if self.session is None:
session_interface = self.app.session_interface
self.session = session_interface.open_session(
self.app, self.request
) if self.session is None:
self.session = session_interface.make_null_session(self.app)

备注:

之前有提到过, web 服务器与 web 框架是分开的,而且 WSGI 也不支持异步服务器。当 web 服务器是异步服务器时,因为 flask 存在线程级全局变量, 且是基于 Werkzeug 中基于 greenlet 的 LocalStack 上实现,所以当异步服务器不是基于 greenlet 时,会存在一定问题。

最新文章

  1. SSH批量部署服务
  2. 下载app后自动安装程序
  3. IOCP入门
  4. django的views里面的request对象详解大全
  5. html-制作导航菜单
  6. JNI调用测试
  7. Oracle 排序分析函数之ROW_NUMBER、RANK和DENSE_RANK
  8. Keepass TAN 记录的使用
  9. oracle数组定义与使用
  10. 怎么在Ubuntu Scope中获取location地址信息
  11. WebService支持多平台上传文件的实现
  12. Python3基础 setdefault() 根据键查找值,找不到键会添加
  13. js promise看这篇就够了
  14. 第一章 jQuery基础
  15. pytorch识别CIFAR10:训练ResNet-34(数据增强,准确率提升到92.6%)
  16. HTML5-之workers(多线程执行)
  17. MyBatis源码解析(十二)——binding绑定模块之MapperRegisty
  18. springboot No Identifier specified for entity的解决办法
  19. quora 的东西就是不一样
  20. centos6.8上yum安装zabbix3.2

热门文章

  1. SQL server T-sql语句查询执行顺序
  2. 以太坊系列之十四: solidity特殊函数
  3. Deferred Shading,延迟渲染(提高渲染效率,减少多余光照计算)【转】
  4. nginx理解与配置
  5. javascript正则表达式——元字符
  6. 洛谷P4502 [ZJOI2018]保镖(计算几何+三维凸包)
  7. Linux--CentOS7使用firewalld打开关闭防火墙与端口
  8. JDBC_事务概念_ACID特点_隔离级别_提交commit_回滚rollback
  9. express + vue 项目搭建
  10. HTML5 indexedDb 数据库