看bottle源码的时候,发现有用到wsgiref模块,就顺带看了wsgiref的实现,内容并不完整。记录下
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")]
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
if __name__ == "__name__":
with make_server('', 8000, demo_app) as httpd:
sa = httpd.socket.getsockname()
print("Serving HTTP on", sa[0], "port", sa[1], "...")
import webbrowser
webbrowser.open('http://localhost:8000/xyz?abc')
httpd.handle_request() # serve one request, then exit
基本的调用就这样子,make_server构造服务,默认使用WSGIServer,请求处理默认使用WSGIRequestHandler,这两个类还会涉及其他的调用,细节会慢慢展开来写
wsgi层由wsgiref模块实现
http层由http模块实现
tcp/udp层由socketserver模块实现
从图中可以看出WSGIServer和WSGIRequestHandler的继承关系,本质是继承于python的socketserver库的BaseServer和BaseRequestHandler
WSGIServer的细节,如下
- 初始化WSGIServer,赋值给server变量。依据继承关系,可以看出WSGIServer的初始化其实是调用的BaseServer的__init__方法。而且BaseServer实现了__enter__和__exit__方法,所以这个server对象可以使用with语句进行调用
- server调用了set_app方法,这个方法是将demo_app设置成server对象的属性(self.application).
- 返回server.
依据继承关系可以看出WSGIServer->HTTPServer->TCPServer都实现了server_bind方法,查看源码的时候发现,基本上是下边这个样子
class TCPServer(BaseServer):
def server_bind(self):
# tcp绑定主机和端口
class HTTPServer(TCPServer):
def server_bind(self):
TCPServer.server_bind(self)
# 定义server_name
# 定义server_port
class WSGIServer(HTTPServer):
def server_bind(self):
HTTPServer.server_bind(self)
# 设置wsgi环境变量
基本上各层干各层的工作,tcp层负责绑定地址和端口号,设置socket相关的选项;http层在tcp层的基础上再设置了server_name和server_port; wsgi层实现了wsgi协议相关的参数设定
handle_request方法是由BaseServer实现的,其中主要的调用流程如下:
- handler_request中,使用了selector模块来监听文件描述符。这里不原样复制源码了,摘抄了其中的一部分:
# selectors是对python select的封装,用于实现非阻塞的socket
with selectors.PollSelector as selector:
# 注册一个文件对象,server_instance既可以是一个fd,也可以是一个实现了fileno()方法的对象,
# server_instance是BaseServer的实例,而BaseServer实现了fileno()方法
selector.register(server_instance, selectors.EVENT_READ)
while True:
ready = selector.select(timeout) # 用于选择满足我们监听的event的文件对象
if ready:
return self._handle_request_noblock()
- _handle_request_noblock定义了请求的处理流程,接收请求->验证请求->处理请求
- get_request是对socket.accept()的封装
- verify_request验证请求,默认返回True
- process_request处理请求,主要是结束请求(用结束可能不太合适)->关闭请求
- process_request
- finish_reuqest是将BaseServer的实例作为参数传递给RequestHandlerClass进行实例化
- shutdown_reqeust
- shutdown_reqeust
- close_request对close_request的封装
- close_request
- 关闭请求
make_server函数中传入了一个默认的handler_class即WSGIRequestHandler类。这个类会作为BaseServer实例的RequestHandlerClass实例属性。当调用finish_request的时候,会对WSGIRequestHandler进行实例化,依据继承关系可得,本质上是由socketserver.py中的BaseRequestHandler来实现实例化。
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()
def setup(self):
pass
def handle(self):
pass
def finish(self):
pass
request、client_address本质上是socket.accept()的返回值,server这里就是BaseServer的实例,接下来还执行了setup()和handle()两个方法。
其中setup()由StreamRequestHandler实现,这个方法执行后会给BaseRequestHandler实例添加connnection、wfile、rfile三个实例属性
handle()由WSGIRequestHandler实现,这个方法中引入了ServerHandler类
finish_content(),会将self.result内容输出wfile中,即StreamRequestHandler的wfile