WebServer和App的那些事
webserver服务器与python app的联系是比较简单的。根据WSGI接口协议,
App端只要定义def simple_app(environ, start_response)
一个接口两个参数的callable obj就可以了。
在WebServer端则需要:
import os, sys
def run_with_cgi(application):
environ = dict(os.environ.items())
environ['wsgi.input'] = sys.stdin
if environ.get('HTTPS', 'off') in ('on', '1'):
environ['wsgi.url_scheme'] = 'https'
else:
environ['wsgi.url_scheme'] = 'http'
headers_set = []
headers_sent = []
def write(data):
if not headers_set:
raise AssertionError("write() before start_response()")
elif not headers_sent:
status, response_headers = headers_sent[:] = headers_set
sys.stdout.write('Status: %s\r\n' % status)
for header in response_headers:
sys.stdout.write('%s: %s\r\n' % header)
sys.stdout.write('\r\n')
sys.stdout.write(data)
sys.stdout.flush()
def start_response(status, response_headers, exc_info=None):
if exc_info:
try:
if headers_sent:
raise exc_info[0], exc_info[1], exc_info[2]
finally:
exc_info = None # avoid dangling circular ref
elif headers_set:
raise AssertionError("Headers already set!")
headers_set[:] = [status, response_headers]
return write
result = application(environ, start_response)
try:
for data in result:
if data:
write(data)
if not headers_sent:
write('')
finally:
if hasattr(result, 'close'):
result.close()
那么问题来了flask中的simple_server
是怎么实现这个接口呢。先上一张图
大概步骤:
1·WSGIServer持有一个app实例
class BaseWSGIServer(HTTPServer, object):
multithread = False
multiprocess = False
request_queue_size = LISTEN_QUEUE
def __init__(self, host, port, app, handler=None,
passthrough_errors=False, ssl_context=None, fd=None):
if handler is None:
handler = WSGIRequestHandler
HTTPServer.__init__(self, (host, int(port)), handler)
self.app = app
2·当一个request到达的时候BaseServer
进行处理,最终执行finish_request
函数,将request
,client_addr
, Server类
传入初始化WSGIRequestHandler
def serve_forever(self, poll_interval=0.5):
self.__is_shut_down.clear()
try:
while not self.__shutdown_request:
r, w, e = _eintr_retry(select.select, [self], [], [],
poll_interval)
if self in r:
self._handle_request_noblock()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
self.RequestHandlerClass(request, client_address, self)
3·RequestHandler对request进行处理,调用实例的handle
方法。
class BaseRequestHandler:
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish()
4·执行WSGIRequestHandler
的handle
和hander_one_request
方法
def handle(self):
rv = None
try:
rv = BaseHTTPRequestHandler.handle(self)
except (socket.error, socket.timeout) as e:
self.connection_dropped(e)
return rv
def handle_one_request(self):
self.raw_requestline = self.rfile.readline()
if not self.raw_requestline:
self.close_connection = 1
elif self.parse_request():
return self.run_wsgi()
5·在’run_wsgi’函数里面就是执行上面的所说的WebServer端应该执行的流程,主要就是调用rv = application(environ, start_response)
这个函数,让app处理,并返回response。