WSGI(全称Web Server Gateway Interface
),是为 Python 语言定义的Web服务器
和Web应用程序
之间的一种简单而通用的接口
,它封装了接受HTTP请求
、解析HTTP请求
、发送HTTP
,响应
等等的这些底层的代码和操做,使开发者能够高效的编写Web应用。php
一个简单的使用WSGI的App例子:html
def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) 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
直接调用和提供参数。WSGIREF
的WSGI Server
,不过性能不是很好,通常只用在开发环境。能够选择其余的如Gunicorn
。Flask有两种Context
(上下文),分别是python
RequestContext
请求上下文Request
请求的对象,封装了Http请求(environ
)的内容Session
根据请求中的cookie,从新载入该访问者相关的会话信息。AppContext
程序上下文g
处理请求时用做临时存储的对象。每次请求都会重设这个变量current_app
当前激活程序的程序实例生命周期:浏览器
current_app
的生命周期最长,只要当前程序实例还在运行,都不会失效。Request
和g
的生命周期为一次请求期间,当请求处理完成后,生命周期也就完结了Session
就是传统意义上的session了。只要它还未失效(用户未关闭浏览器、没有超过设定的失效时间),那么不一样的请求会共用一样的session。Flask根据WSGI Server封装的请求等的信息(environ
)新建RequestContext对象
和AppContext对象
ruby
# 声明对象 # LocalStack LocalProxy 都由Werkzeug提供 # 咱们不深究他的细节,那又是另一个故事了,咱们只需知道他的做用就好了 # LocalStack 是栈结构,能够将对象推入、弹出 # 也能够快速拿到栈顶对象。固然,全部的修改都只在本线程可见。 _request_ctx_stack = LocalStack() _app_ctx_stack = LocalStack() # 若是调用一个LocalStack实例, 能返回一个 LocalProxy 对象 # 这个对象始终指向 这个LocalStack实例的栈顶元素。 # 若是栈顶元素不存在,访问这个 LocalProxy 的时候会抛出 RuntimeError异常 # LocalProxy对象你只需暂时理解为栈里面的元素便可了 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'))
# 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 self.url_adapter = app.create_url_adapter(self.request) self.flashes = None self.session = None
#AppContext class AppContext(object): def __init__(self, app): self.app = app self.url_adapter = app.create_url_adapter(None) self.g = app.app_ctx_globals_class() self._refcnt = 0
这里须要注意的是,RequestContext
在初始化的时候,当前Flask的实例做为参数被传进来。虽然每次的请求处理都会建立一个RequestContext对象,可是每一次传入的app参数倒是同一个。经过这个机制,可使得:bash
由同一个Flask实例所建立的
RequestContext
,其成员变量app都是同一个Flask实例对象 。实现了多个RequestContext
对应同一个current_app
的目的。服务器
将RequestContext
对象push进_request_ctx_stack
里面。在此次请求期间,访问request对象
,session对象
将指向这个栈的栈顶元素cookie
class RequestContext(object): def push(self): .... _app_ctx_stack.push(self) appcontext_pushed.send(self.app)
AppContext对象push进_app_ctx_stack
里面。在此次请求期间,访问g
对象将指向这个栈的栈顶元素session
class AppContext(object): def push(self): .... _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
栈。app
此次HTTP的响应已经生成了,就不须要两个上下文对象了。分别将两个上下文对象出栈,为下一次的HTTP请求作出准备。
调用Response对象,向WSGI Server返回其结果做为HTTP正文。Response对象是一个 可调用对象,当调用发生时,将首先执行WSGI服务器传入的start_response()函数 发送状态码和HTTP报文头。
最后附上Flask处理请求的wsgi_app
函数
# environ: WSGI Server封装的HTTP请求信息 # start_response: WSGI Server提供的函数,调用能够发送状态码和HTTP报文头 def wsgi_app(self, environ, start_response): # 根据environ建立上下文 ctx = self.request_context(environ) # 把当前的request context,app context绑定到当前的context ctx.push() error = None try: try: #根据请求的URL,分发请求,通过视图函数处理后返回响应对象 response = self.full_dispatch_request() except Exception as e: error = e response = self.make_response(self.handle_exception(e)) return response(environ, start_response) finally: if self.should_ignore_error(error): error = None # 最后出栈 ctx.auto_pop(error)