本文介绍了 WSGI 是什么以及 WSGI 的处理流程。python
服务器网关接口(WSGI)是 web 服务器和 web 应用(或 Python 框架)之间的接口规范,旨在提升 web 应用在 web 服务器上的可迁移性。若是一个应用遵循了 WSGI 规范,那么这个应用能够运行在任何遵循 WSGI 规范的服务器上。web
服务器指任何实现了 WSGI 规范的服务器,好比 Gunicorn、uWSGI。服务器
WSGI 有两端:app
服务器调用一个由应用端提供的可调用对象。由服务器定义客户端应该如何提供这个对象。好比一些服务器须要应用的部署者去写一个简短的脚原本建立一个服务器的实例,并向服务器实例提供应用对象。另外一些服务器可能使用配置文件或者其余机制来指定应用对象应该从哪里导入。框架
除了单纯的服务器和应用端,也能够建立一个中间件来实现两边的定义。这样的组件对于服务器来讲是应用端,而对于应用端来讲是服务器,而且能够被用来提供扩展 APIs、内容转换、导航和其余功能。函数
可调用对象能够指一个函数、方法、类或者一个拥有 __call__
方法的实例。由服务器或实现其的应用端来选择针对他们需求的合适技术。相反的,一个执行可调用对象的服务器或者客户端对提供给它们的可调用对象不能有任何假设。可调用对象只是被用来调用,不须要检查它。ui
以请求数据组成的字典
和处理函数
的应用可调用对象若是有中间件,那么中间件位于服务器和应用之间,中间件相对于服务器是应用,相对于应用是服务器。this
WSGI 定义了两种字符串:.net
str
)bytes
实现,Python 2 使用 str
),用于请求和响应的 body(好比 POST/PUT 的输入数据和 HTML 输出)['str1', 'str2', ]
)做为响应体应用对象必须能够被执行屡次,实际上全部的服务器(除了 CGI) 都会发送重复的请求。code
每当服务器收到一个 HTTP 客户端的请求,服务器会执行应用的可调用对象。获取结果后,将其发送给客户端。
定义可调用应用对象,并启动 WSGI 服务器:
#! /usr/bin/env python # Python's bundled WSGI server from wsgiref.simple_server import make_server def application(environ, start_response): # Sorting and stringifying the environment key, value pairs response_body = [ '%s: %s' % (key, value) for key, value in sorted(environ.items()) ] response_body = '\n'.join(response_body) # Response body must be bytes response_body = response_body.encode() status = '200 OK' response_headers = [ ('Content-Type', 'text/plain'), ('Content-Length', str(len(response_body))) ] start_response(status, response_headers) return [response_body] # Instantiate the server httpd = make_server( 'localhost', # The host name 8051, # A port number where to wait for the request application # The application object name, in this case a function ) # Wait for a single request, serve it and quit httpd.handle_request()
以上代码来自 http://wsgi.tutorial.codepoint.net/environment-dictionary
启动 WSGI 服务后,访问 http://localhost:8051/ 可得到响应。
服务器调用应用获得响应后,将其发送给客户端
# 来自 wsgiref.handlers.BaseHandler#finish_response def finish_response(self): try: if not self.result_is_file() or not self.sendfile(): for data in self.result: self.write(data) self.finish_content() finally: self.close()