Bottle的一个优势是适配很多支持WSGI的Server,主要有默认是用wsgiref,CherryPy,Gunicorn,Tornado,Eventlet和Gevent。
Bottle中定义了ServerAdapter基类,通过继承这个基类,可以适配很多的WSGI Server。通过将解析完的app对象以及相关的host,port等参数传递给ServerAdapter的子类,再通过各个Server特有的启动方式,根据指定的参数启动WSGI Server。
例如,WSGIRefefServer的实现就是这样的(直接从源码中copy过来)
class WSGIRefServer(ServerAdapter):
def run(self, app): # pragma: no cover
from wsgiref.simple_server import make_server
from wsgiref.simple_server import WSGIRequestHandler, WSGIServer
import socket
class FixedHandler(WSGIRequestHandler):
def address_string(self): # Prevent reverse DNS lookups please.
return self.client_address[0]
def log_request(*args, **kw):
if not self.quiet:
return WSGIRequestHandler.log_request(*args, **kw)
handler_cls = self.options.get('handler_class', FixedHandler)
server_cls = self.options.get('server_class', WSGIServer)
if ':' in self.host: # Fix wsgiref for IPv6 addresses.
if getattr(server_cls, 'address_family') == socket.AF_INET:
class server_cls(server_cls):
address_family = socket.AF_INET6
self.srv = make_server(self.host, self.port, app, server_cls,
handler_cls)
self.port = self.srv.server_port # update port actual port (0 means random)
try:
self.srv.serve_forever()
except KeyboardInterrupt:
self.srv.server_close() # Prevent ResourceWarning: unclosed socket
raise
Bottle中还提供了一个AutoServer,这个server会从几个默认的WSGI Server中尝试进行启动,直到第一个成功的为止。利用AutoServer的这个特性,可以很自由的在几个WSGI Server之间进行切换,而不必更改自己的代码。比如本机的环境(开发环境)可以安装WSGIRef,但是到了线上环境我们直接选择安装CherryPy,这样就能直接将WSGI Server切换到CherryPy,而且应用的代码不需要做任何改动。AutoServer的代码实现如下:
class AutoServer(ServerAdapter):
""" Untested. """
adapters = [WaitressServer, PasteServer, TwistedServer, CherryPyServer,
WSGIRefServer]
def run(self, handler):
for sa in self.adapters:
try:
return sa(self.host, self.port, **self.options).run(handler)
except ImportError:
pass