关于WSGI

WSGI(全称Web Server Gateway Interface),是为 Python 语言定义的Web服务器Web应用程序之间的一种简单而通用的接口,它封装了接受HTTP请求解析HTTP请求发送HTTP响应等等的这些底层的代码和操作,使开发者可以高效的编写Web应用。

一个简单的使用WSGI的App例子:

  1. def application(environ, start_response):
  2. start_response('200 OK', [('Content-Type', 'text/html')])
  3. return [b'<h1>Hello, I Am WSGI!</h1>']
  • environ: 一个包含全部HTTP请求信息的字典,由WSGI Server解包HTTP请求生成。
  • start_response: 一个WSGI Server提供的函数,调用可以发送响应的状态码和HTTP报文头, 函数在返回前必须调用一次start_response()
  • application()应当返回一个可以迭代的对象(HTTP正文)。
  • application()函数由WSGI Server直接调用和提供参数。
  • Python内置了一个WSGIREFWSGI Server,不过性能不是很好,一般只用在开发环境。可以选择其他的如Gunicorn
 
WSGI Server 和 App交互图

Flask的上下文对象

Flask有两种Context(上下文),分别是

  • RequestContext 请求上下文
  • Request 请求的对象,封装了Http请求(environ)的内容
  • Session 根据请求中的cookie,重新载入该访问者相关的会话信息。
  • AppContext 程序上下文
  • g 处理请求时用作临时存储的对象。每次请求都会重设这个变量
  • current_app 当前激活程序的程序实例

生命周期:

  • current_app的生命周期最长,只要当前程序实例还在运行,都不会失效。
  • Requestg的生命周期为一次请求期间,当请求处理完成后,生命周期也就完结了
  • Session就是传统意义上的session了。只要它还未失效(用户未关闭浏览器、没有超过设定的失效时间),那么不同的请求会共用同样的session。

Flask处理流程

 
Flask处理请求流程

第一步:创建上下文

Flask根据WSGI Server封装的请求等的信息(environ)新建RequestContext对象AppContext对象

  1. # 声明对象
  2. # LocalStack LocalProxy 都由Werkzeug提供
  3. # 我们不深究他的细节,那又是另外一个故事了,我们只需知道他的作用就行了
  4. # LocalStack 是栈结构,可以将对象推入、弹出
  5. # 也可以快速拿到栈顶对象。当然,所有的修改都只在本线程可见。
  6. _request_ctx_stack = LocalStack()
  7. _app_ctx_stack = LocalStack()
  8. # 如果调用一个LocalStack实例, 能返回一个 LocalProxy 对象
  9. # 这个对象始终指向 这个LocalStack实例的栈顶元素。
  10. # 如果栈顶元素不存在,访问这个 LocalProxy 的时候会抛出 RuntimeError异常
  11. # LocalProxy对象你只需暂时理解为栈里面的元素即可了
  12. current_app = LocalProxy(_find_app)
  13. request = LocalProxy(partial(_lookup_req_object, 'request'))
  14. session = LocalProxy(partial(_lookup_req_object, 'session'))
  15. g = LocalProxy(partial(_lookup_app_object, 'g'))
  1. # RequestContext
  2. class RequestContext(object):
  3. def __init__(self, app, environ, request=None):
  4. self.app = app
  5. if request is None:
  6. request = app.request_class(environ)
  7. self.request = request
  8. self.url_adapter = app.create_url_adapter(self.request)
  9. self.flashes = None
  10. self.session = None
  1. #AppContext
  2. class AppContext(object):
  3. def __init__(self, app):
  4. self.app = app
  5. self.url_adapter = app.create_url_adapter(None)
  6. self.g = app.app_ctx_globals_class()
  7. self._refcnt = 0

这里需要注意的是,RequestContext在初始化的时候,当前Flask的实例作为参数被传进来。虽然每次的请求处理都会创建一个RequestContext对象,但是每一次传入的app参数却是同一个。通过这个机制,可以使得:

由同一个Flask实例所创建的RequestContext,其成员变量app都是同一个Flask实例对象 。实现了多个RequestContext对应同一个current_app 的目的。

第二步:入栈

RequestContext对象push进_request_ctx_stack里面。在这次请求期间,访问request对象session对象将指向这个栈的栈顶元素

  1. class RequestContext(object):
  2. def push(self):
  3. ....
  4. _app_ctx_stack.push(self)
  5. appcontext_pushed.send(self.app)

AppContext对象push进_app_ctx_stack里面。在这次请求期间,访问g对象将指向这个栈的栈顶元素

  1. class AppContext(object):
  2. def push(self):
  3. ....
  4. _request_ctx_stack.push(self)

第三步:请求分发

response = self.full_dispatch_request()
Flask将调用full_dispatch_request函数进行请求的分发,之所以不用给参数,是因为我们可以通过request对象获得这次请求的信息。full_dispatch_request将根据请求的url找到对应的蓝本里面的视图函数,并生成一个response对象。注意的是,在请求之外的时间,访问request对象是无效的,因为request对象依赖请求期间的_request_ctx_stack栈。

第四步:上下文对象出栈

这次HTTP的响应已经生成了,就不需要两个上下文对象了。分别将两个上下文对象出栈,为下一次的HTTP请求做出准备。

第五步:响应WSGI

调用Response对象,向WSGI Server返回其结果作为HTTP正文。Response对象是一个 可调用对象,当调用发生时,将首先执行WSGI服务器传入的start_response()函数 发送状态码和HTTP报文头。

最后附上Flask处理请求的wsgi_app函数

  1. # environ: WSGI Server封装的HTTP请求信息
  2. # start_response: WSGI Server提供的函数,调用可以发送状态码和HTTP报文头
  3. def wsgi_app(self, environ, start_response):
  4. # 根据environ创建上下文
  5. ctx = self.request_context(environ)
  6. # 把当前的request context,app context绑定到当前的context
  7. ctx.push()
  8. error = None
  9. try:
  10. try:
  11. #根据请求的URL,分发请求,经过视图函数处理后返回响应对象
  12. response = self.full_dispatch_request()
  13. except Exception as e:
  14. error = e
  15. response = self.make_response(self.handle_exception(e))
  16. return response(environ, start_response)
  17. finally:
  18. if self.should_ignore_error(error):
  19. error = None
  20. # 最后出栈
  21. ctx.auto_pop(error)

flask请求和应用上下文的更多相关文章

  1. Flask请求和应用上下文源码分析

      flask的request和session设置方式比较新颖,如果没有这种方式,那么就只能通过参数的传递. flask是如何做的呢? 1:本地线程,保证即使是多个线程,自己的值也是互相隔离 1 im ...

  2. 02 flask 请求钩子、异常捕获、上下文、Flask-Script 扩展、jinja2 模板引擎、csrf防范

    一 请求勾子 在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如: 在请求开始时,建立数据库连接: 在请求开始时,根据需求进行权限校验: 在请求结束时,指定数据的交互格式: 为了让每个 ...

  3. Flask(4)- flask请求上下文源码解读、http聊天室单聊/群聊(基于gevent-websocket)

    一.flask请求上下文源码解读 通过上篇源码分析,我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(en ...

  4. flask 请求上下文源码(转)

    本篇阅读目录 一.flask请求上下文源码解读 二.http聊天室(单聊/群聊)- 基于gevent-websocket 回到顶部 转:https://www.cnblogs.com/li-li/p/ ...

  5. Flask的请求钩子与上下文简览

    请求钩子(Hook) 在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如:在请求开始时,建立数据库连接:在请求结束时,指定数据的交互格式.为了让>每个视图函数避免编写重复功能的代 ...

  6. flask请求钩子、HTTP响应、响应报文、重定向、手动返回错误码、修改MIME类型、jsonify()方法

    请求钩子: 当我们需要对请求进行预处理和后处理时,就可以用Flask提供的回调函数(钩子),他们可用来注册在请求处理的不同阶段执行的处理函数.这些请求钩子使用装饰器实现,通过程序实例app调用,以 b ...

  7. flask请求访问数据

    flask请求访问数据 在flask框架中,访问请求数据由全局的request对象来提供,在flask框架中,request对象具有 全局作用域: from flask import request ...

  8. flask请求上下文

    先看一个例子: #!/usr/bin/env python # -*- coding:utf-8 -*- import threading # local_values = threading.loc ...

  9. flask 请求上下文

    一篇引用大牛的 https://www.cnblogs.com/zhaopanpan/p/9457343.html ### 线程安全 ```python# 线程不安全class Foo(object) ...

随机推荐

  1. spark读取本地文件

    /** * Read a text file from HDFS, a local file system (available on all nodes), or any * Hadoop-supp ...

  2. Unity3D中UGUI使用ScrollBar之后保存,工程启动报错原因跟踪

    笔者不久前将Unity3D版本更新为4.6.2之后.在使用新UI的时候发现关闭项目之后经常再次打开项目会出现一对的报错. 找了一圈,发现是ScrollBar控件出现了BUG.整个空间的滑块消失了. 在 ...

  3. repcached与mysql缓存測试

    使用gem安装mysql引擎 gem install mysql(假设安装失败.请查找一些依赖组建是否安装,比如mysql-devel) 编写ruby脚本,先获取mysql数据,之后从memcache ...

  4. Python之修改文件MD5值

    import os def fileAppend(filename): myfile = open(filename,'a') myfile.write("####&&&am ...

  5. web页面防盗链功能使用--request.getHeader("Referer")

    使用Request对象设置页面的防盗链 所谓的防盗链就是当你以一个非正常渠道去访问某一个Web资源的时候,服务器会将你的请求忽略并且将你的当前请求变为按正常渠道访问时的请求并返回到相应的页面,用户只有 ...

  6. 【转】crontab命令 脚本定时运行

    一.crond简介 crond是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动cro ...

  7. Android Studio 编写 JNI

    之前一直都不知怎么编写JNI,今天刚好学习一下,感谢梦真的指教,以及提供的文档. 参考链接 http://blog.csdn.net/u011168565/article/details/518781 ...

  8. IoC就是IoC,不是什么技术,与GoF一样,是一种设计模式。

    IoC就是IoC,不是什么技术,与GoF一样,是一种设计模式. InterfaceDrivenDesign接口驱动,接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性等等,但是接口一 ...

  9. MVC已经是现代Web开发中的一个很重要的部分,下面介绍一下Spring MVC的一些使用心得。

    MVC已经是现代Web开发中的一个很重要的部分,下面介绍一下Spring MVC的一些使用心得. 之前的项目比较简单,多是用JSP .Servlet + JDBC 直接搞定,在项目中尝试用 Strut ...

  10. 关于CentOS系统中,文件权限第11位上是一个点的解读

    http://blog.csdn.net/dashuai03091199/article/details/38920833 http://blog.csdn.net/xinlongabc/articl ...