WSGI启动
基于django启动命令python manage.py runserver,在调用到Command中的**inner_run()**方法的时候创建了handler
# C:\pyenvs\mysite\Lib\site-packages\django\core\management\commands\runserver.py
class Command(BaseCommand):
...
def inner_run(self, *args, **options):
...
try:
# self.get_handler返回了一个WSGI handler
handler = self.get_handler(*args, **options) # next step
run(self.addr, int(self.port), handler,
ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
except OSError as e:
...
except KeyboardInterrupt:
if shutdown_message:
self.stdout.write(shutdown_message)
sys.exit(0)
接下来看看self.get_handler
def get_handler(self, *args, **options):
"""Return the default WSGI handler for the runner."""
# options: {'verbosity': 1, 'settings': None, 'pythonpath': None, 'traceback': False, 'no_color': False, 'force_color': False, 'addrport': None, 'use_ipv6': False, 'use_threading': True, 'use_reloader': True, 'use_static_handler': True, 'insecure_serving': False}
return get_internal_wsgi_application() # next step
# 调用的basehttp模块中的get_internal_wsgi_application方法
# C:\pyenvs\mysite\Lib\site-packages\django\core\servers\basehttp.py
def get_internal_wsgi_application():
# settings: <Settings "mysite.settings">
# app_path: 'mysite.wsgi.application'
from django.conf import settings
app_path = getattr(settings, 'WSGI_APPLICATION')
if app_path is None:
return get_wsgi_application()
# C:\pyenvs\mysite\Lib\site-packages\django\core\wsgi.py
def get_wsgi_application():
...
django.setup(set_prefix=False)
return WSGIHandler()
>self.get_handler()返回了一个WSGI可调用对象。避免了django.core.handler.WSGIHandler成为公共API,以防内部WSGI实现在未来发生变化或移动
接下来继续回到Command(BaseCommand)中的inner_run()方法,在get_handler()方法获取到一个WSGI handler之后,执行了run方法
class Command(BaseCommand):
help = "Starts a lightweight Web server for development."
# Validation is called explicitly each time the server is reloaded.
requires_system_checks = []
stealth_options = ('shutdown_message',)
default_addr = '127.0.0.1'
default_addr_ipv6 = '::1'
default_port = '8000'
protocol = 'http'
# django自定义类,实现python WSGI协议的BaseHTTPServer
# mro:WSGIServer>simple_server.WSGIServer>HTTPServer>socket.TCPServer>BaseServer
server_cls = WSGIServer
def inner_run(self, *args, **options):
try:
# self.get_handler返回了一个WSGI handler
handler = self.get_handler(*args, **options)
# handler: <django.contrib.staticfiles.handlers.StaticFilesHandler object at 0x000002496F7DD388>
# server_cls是WSGIServer类的一个实例(封装了底层tcp)
run(self.addr, int(self.port), handler,
ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
except OSError as e:
...
接下来继续执行**run()**方法
# C:\pyenvs\mysite\Lib\site-packages\django\core\management\commands\runserver.py
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
# server_address ('127.0.0.1', 8000)
server_address = (addr, port)
if threading:
httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
else:
httpd_cls = server_cls
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6) # next step
...
httpd.set_app(wsgi_handler)
httpd.serve_forever()
先看http_cls,其实就是WSGIServer类,接收了server_address, WSGIRequestHandler, ipv6=ipv6参数,最终返回了httpd
看看WSGIRequestHandler类是什么
# C:\pyenvs\mysite\Lib\site-packages\django\core\servers\basehttp.py
class WSGIRequestHandler(simple_server.WSGIRequestHandler):
# django自定义的WSGIRequestHandler类的,继承自simple_server的WSGIReuquestHandler类
# 声明了http协议的版本
protocol_version = 'HTTP/1.1'
...
def log_message(self, format, *args):
# 定义日志格式
...
level(format, *args, extra=extra)
def get_environ(self):
# 调用了父类的get_environ方法,wsgiref模块中的WSGIRequestHandler类的get_environ()方法构造了字典
for k in self.headers:
if '_' in k:
del self.headers[k]
return super().get_environ()
# handle()方法在WSGIRequestHandler的__init__()方法中被调用
'''
class WSGIRequestHandler(BaseHTTPRequestHandler):
server_version: str
def get_environ(self) -> WSGIEnvironment: ...
def get_stderr(self) -> ErrorStream: ...
def handle(self) -> None: ...
'''
def handle(self):
self.close_connection = True
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
try:
self.connection.shutdown(socket.SHUT_WR)
except (AttributeError, OSError):
pass
def handle_one_request(self):
"""Copy of WSGIRequestHandler.handle() but with different ServerHandler"""
# raw_requestline是客户端发来的请求行数据,读取请求行信息,其实这里读取的并不仅仅是请求行,而是
# 读取了65537字节的数据到rfile这个缓冲输入流中,在parse_request()方法中都会对这个raw_requestline
# 信息用"\r\n"来分割,取出第一行,也就是指取出请求行的信息。
self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536:
self.requestline = ''
self.request_version = ''
self.command = ''
self.send_error(414)
return
# parse_request解析socket对象接收到http请求报文信息,赋值给自己的属性
if not self.parse_request(): # An error code has been sent, just exit
return
# 实例化ServerHandler,django的WSGIHandler中传入的start_reponse对象就是这个handler
handler = ServerHandler(
self.rfile, self.wfile, self.get_stderr(), self.get_environ()
)
handler.request_handler = self # backpointer for logging & connection closing
# 调用application(environ, start_reponse)
handler.run(self.server.get_app())
django自定义WSGIRequestHandler中 handle_one_request方法中实例化ServerHandler,并调用了**run()**方法
看下ServerHandler是什么
# C:\pyenvs\mysite\Lib\site-packages\django\core\servers\basehttp.py
class ServerHandler(simple_server.ServerHandler):
http_version = '1.1'
def __init__(self, stdin, stdout, stderr, environ, **kwargs):
try:
content_length = int(environ.get('CONTENT_LENGTH'))
except (ValueError, TypeError):
content_length = 0
super().__init__(LimitedStream(stdin, content_length), stdout, stderr, environ, **kwargs)
def cleanup_headers(self):
super().cleanup_headers()
# HTTP/1.1 requires support for persistent connections. Send 'close' if
# the content length is unknown to prevent clients from reusing the
# connection.
if 'Content-Length' not in self.headers:
self.headers['Connection'] = 'close'
# Persistent connections require threading server.
elif not isinstance(self.request_handler.server, socketserver.ThreadingMixIn):
self.headers['Connection'] = 'close'
# Mark the connection for closing if it's set as such above or if the
# application sent the header.
if self.headers.get('Connection') == 'close':
self.request_handler.close_connection = True
def close(self):
self.get_stdin()._read_limited()
super().close()
def handle_error(self):
# Ignore broken pipe errors, otherwise pass on
if not is_broken_pipe_error():
super().handle_error()
WSGIServer:
django自定义的类,创建基于WSGI协议BaseHTTPServer
继承mro: WSGIServer>simple_server.WSGIServer>HTTPServer>socket.TCPServer>BaseServer
WSGIRequestHandler:
- 实例化socket对象封装成的rfile,wfile对象,(rfile,wfile都是带缓冲的IO流对象)。用于接收和发送数据给客户端
- 提供get_environ()来构造environ字典
- 实例化的时候调用自己重写的handler()方法,将BaseHandler的子类实例化。同时传入rfile, wfile, environ参数
ServerHandler,继承自BaseHandler:
- 实例化时,接受WSGIRequestHandler对象的rfile,wfile,environ作为初始化参数
- 调用自己的run(application)来调用application(environ, start_reponse)
- 调用自己的finsh_response()来处理application(environ, start_reponse)返回响应对象repoonse,迭代response对象中存放的数据发送给客户端
总结:
-
Command执行inner_run方法
def inner_run(self, *args, **options): ... handler = self.get_handler(*args, **options) run(self.addr, int(self.port), handler, ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls) ...
-
获取handler
- 调用get_handler方法获取handler, handler是一个WSGI handler
- get_handler方法调用get_internal_wsgi_application方法
- get_internal_wsgi_application方法返回WSGIHander()类实例
-
执行run方法
- run方法参数 self.server_cls: django自定义的WSGIServer类
- WSGIServer实现了WSGI协议的BaseHTPPServer
- WSGIServer的mro: WSGIServer>simple_server.WSGIServer>HTTPServer>socket.TCPServer>BaseServer
-
-
调用inner_run中的run()方法
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer): server_address = (addr, port) if threading: httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {}) else: httpd_cls = server_cls httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6) if threading: httpd.daemon_threads = True httpd.set_app(wsgi_handler) httpd.serve_forever()
- httpd_cls是WSGIServer类
- WSIGIServer接收参数WSGIRequestHandler参数
- WSGIRequestHandler是django自定义的类,重写父类handler()方法。作为参数传入WSGIServer类中
- 实例化的时候会把socket对象分别封装成rfile和wfile对象,他们都是带换成的io流对象,用于接收和发送数据给客户端
rfile: 读取客户端的请求信息
wfile: 写入响应并返回客户端
IO流对象: 一般情况下是磁盘和内存之间输入输出 - 提供了get_environ(), 构造了environ字典
- 当有请求到来时候,就会触发WSGIRequestHandler类实例化,当它被实例化的时候触发handle()方法
WSGIRequestHandler通过调用handle()与ServerHandler对象产生关联
- 当触发handle()方法时,handle方法实例化了ServerHandler()
- ServerHandler()实例化的接收了WSGIRequestHandler封装rfile, wfile对象以及environ作为初始化参数
- ServerHandler()调用内部的run(applicaion)来调用application(environ, start_reponse)
- application(environ, start_reponse)是dajngo框架处理请求的入口,请求处理逻辑就是application(environ, start_reponse)
application是一个WSGIHandler类的实例化对象,application(environ, start_reponse)调用了该对象__call__(environ, start_reponse)
- 接着调用自己的finish_reponse()来处理application(environ, start_reponse)返回的reponse,迭代reponse返回给客户端