首先弄清下面几个概念:
WSGI:全称是Web Server Gateway Interface
,WSGI
不是服务器,python
模块,框架,API
或者任何软件,只是一种规范,描述web server
如何与web application
通讯的规范。server
和application
的规范在PEP 3333中有具体描述。要实现WSGI协议,必须同时实现web server和web application,当前运行在WSGI
协议之上的web
框架有Bottle
, Flask
, Django
。
uwsgi:与WSGI
同样是一种通讯协议,是uWSGI
服务器的独占协议,用于定义传输信息的类型(type of information
),每个uwsgi packet
前4byte
为传输信息类型的描述,与WSGI协议是两种东西,听说该协议是fcgi
协议的10倍快。
uWSGI:是一个web
服务器,实现了WSGI
协议、uwsgi
协议、http
协议等。html
WSGI
协议主要包括server
和application
两部分:python
WSGI server
负责从客户端接收请求,将request
转发给application
,将application
返回的response
返回给客户端;WSGI application
接收由server
转发的request
,处理请求,并将处理结果返回给server
。application
中能够包括多个栈式的中间件(middlewares
),这些中间件须要同时实现server与application,所以能够在WSGI服务器与WSGI应用之间起调节做用:对服务器来讲,中间件扮演应用程序,对应用程序来讲,中间件扮演服务器。WSGI
协议实际上是定义了一种server
与application
解耦的规范,便可以有多个实现WSGI server
的服务器,也能够有多个实现WSGI application
的框架,那么就能够选择任意的server
和application
组合实现本身的web
应用。例如uWSGI
和Gunicorn
都是实现了WSGI server
协议的服务器,Django
,Flask
是实现了WSGI application
协议的web
框架,能够根据项目实际状况搭配使用。nginx
像Django
,Flask
框架都有本身实现的简单的WSGI server
,通常用于服务器调试,生产环境下建议用其余WSGI server
。web
以Django
为例,分析一下WSGI
协议的具体实现过程。django
WSGI application
应该实现为一个可调用对象,例如函数、方法、类(包含**call**
方法)。须要接收两个参数:浏览器
environment
(编码中多简写为environ
、env
)HTTP status
)、响应头(HTTP headers
)的回调函数经过回调函数将响应状态和响应头返回给server
,同时返回响应正文(response body
),响应正文是可迭代的、并包含了多个字符串。下面是Django
中application
的具体实现部分:服务器
class WSGIHandler(base.BaseHandler): initLock = Lock() request_class = WSGIRequest def __call__(self, environ, start_response): # 加载中间件 if self._request_middleware is None: with self.initLock: try: # Check that middleware is still uninitialized. if self._request_middleware is None: self.load_middleware() except: # Unload whatever middleware we got self._request_middleware = None raise set_script_prefix(get_script_name(environ)) # 请求处理以前发送信号 signals.request_started.send(sender=self.__class__, environ=environ) try: request = self.request_class(environ) except UnicodeDecodeError: logger.warning('Bad Request (UnicodeDecodeError)', exc_info=sys.exc_info(), extra={'status_code': 400,}) response = http.HttpResponseBadRequest() else: response = self.get_response(request) response._handler_class = self.__class__ status = '%s %s' % (response.status_code, response.reason_phrase) response_headers = [(str(k), str(v)) for k, v in response.items()] for c in response.cookies.values(): response_headers.append((str('Set-Cookie'), str(c.output(header='')))) # server提供的回调方法,将响应的header和status返回给server start_response(force_str(status), response_headers) if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'): response = environ['wsgi.file_wrapper'](response.file_to_stream) return response
能够看出application
的流程包括:cookie
get_response()
方法处理当前请求,该方法的的主要逻辑是经过urlconf
找到对应的view
和callback
,按顺序执行各类middleware
和callback
。server
传入的start_response()
方法将响应header
与status
返回给server
。负责获取http
请求,将请求传递给WSGI application
,由application
处理请求后返回response
。以Django
内建server
为例看一下具体实现。
经过runserver
运行django
项目,在启动时都会调用下面的run
方法,建立一个WSGIServer
的实例,以后再调用其serve_forever()
方法启动服务。网络
def run(addr, port, wsgi_handler, ipv6=False, threading=False): server_address = (addr, port) if threading: httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {}) else: httpd_cls = WSGIServer # 这里的wsgi_handler就是WSGIApplication httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6) if threading: httpd.daemon_threads = True httpd.set_app(wsgi_handler) httpd.serve_forever()
下面表示WSGI server
服务器处理流程中关键的类和方法。mvc
xiong (2).png-93.7kB
WSGIServer
run()
方法会建立
WSGIServer
实例,主要做用是接收客户端请求,将请求传递给
application
,而后将
application
返回的
response
返回给客户端。
HTTP
请求的handler
:WSGIRequestHandler
类set_app
和get_app
方法设置和获取WSGIApplication
实例wsgi_handler
handler_request
方法,会建立WSGIRequestHandler
实例处理http请求。WSGIServer
中get_request
方法经过socket
接受请求数据WSGIRequestHandler
WSGIServer
在调用handle_request
时建立实例,传入request
、cient_address
、WSGIServer
三个参数,__init__
方法在实例化同时还会调用自身的handle
方法handle
方法会建立ServerHandler
实例,而后调用其run
方法处理请求ServerHandler
WSGIRequestHandler
在其handle
方法中调用run
方法,传入self.server.get_app()
参数,获取WSGIApplication
,而后调用实例(__call__
),获取response
,其中会传入start_response
回调,用来处理返回的header
和status
。application
获取response
之后,经过finish_response
返回response
WSGIHandler
WSGI
协议中的application
,接收两个参数,environ
字典包含了客户端请求的信息以及其余信息,能够认为是请求上下文,start_response
用于发送返回status
和header
的回调函数虽然上面一个WSGI server
涉及到多个类实现以及相互引用,但其实原理仍是调用WSGIHandler
,传入请求参数以及回调方法start_response()
,并将响应返回给客户端。
django
的simple_server.py
模块实现了一个简单的HTTP
服务器,并给出了一个简单的demo
,能够直接运行,运行结果会将请求中涉及到的环境变量在浏览器中展现出来。
其中包括上述描述的整个http
请求的全部组件:
ServerHandler
, WSGIServer
, WSGIRequestHandler
,以及demo_app
表示的简易版的WSGIApplication
。
能够看一下整个流程:
if __name__ == '__main__': # 经过make_server方法建立WSGIServer实例 # 传入建议application,demo_app httpd = make_server('', 8000, demo_app) sa = httpd.socket.getsockname() print("Serving HTTP on", sa[0], "port", sa[1], "...") import webbrowser webbrowser.open('http://localhost:8000/xyz?abc') # 调用WSGIServer的handle_request方法处理http请求 httpd.handle_request() # serve one request, then exit httpd.server_close() def make_server( host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler ): """Create a new WSGI server listening on `host` and `port` for `app`""" server = server_class((host, port), handler_class) server.set_app(app) return server # demo_app可调用对象,接受请求输出结果 def demo_app(environ,start_response): from io import StringIO stdout = StringIO() print("Hello world!", file=stdout) print(file=stdout) h = sorted(environ.items()) for k,v in h: print(k,'=',repr(v), file=stdout) start_response("200 OK", [('Content-Type','text/plain; charset=utf-8')]) return [stdout.getvalue().encode("utf-8")]
demo_app()
表示一个简单的WSGI application实现,经过make_server()
方法建立一个WSGIServer
实例,调用其handle_request()
方法,该方法会调用demo_app()
处理请求,并最终返回响应。
uWSGI
旨在为部署分布式集群的网络应用开发一套完整的解决方案。主要面向web
及其标准服务。因为其可扩展性,可以被无限制的扩展用来支持更多平台和语言。uWSGI
是一个web
服务器,实现了WSGI
协议,uwsgi
协议,http
协议等。
uWSGI
的主要特色是:
app
管理app
的性能和瓶颈)uWSGI
服务器本身实现了基于uwsgi
协议的server
部分,咱们只须要在uwsgi
的配置文件中指定application
的地址,uWSGI
就能直接和应用框架中的WSGI application
通讯。
参考资料:
作python Web开发你要理解:WSGI & uwsgi
WSGI & uwsgi
WSGI Tutorial
打造mvc框架之wsgi协议的优缺点及接口实现
Nginx和uWSGI通讯机制
理解Python WSGI