本文环境python3.5.2,django1.10.x系列
python manage.py runserver 命令启动本地调试服务器后,接着要分析一下django对请求request的整个处理过程,在此感谢在django源码学习中 小屋子大侠 的帮助,
小屋子大侠 博文地址:https://blog.youkuaiyun.com/qq_33339479/article/category/6800733
一、创建WSGIServer
上一节讲到在使用runserver运行Django项目,在启动时会调用django.core.servers.basehttp中的run()方法,创建一个django.core.servers.basehttp.WSGIServer类的实例,之后调用其serve_forever()方法启动HTTP服务。run方法的源码如下:
def run(addr, port, wsgi_handler, ipv6=False, threading=False):
server_address = (addr, port) # 服务端监听的地址和端口
if threading: # 如果多线程运行
httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {}) # 创建WSGIServer服务器,生成一个
else:
httpd_cls = WSGIServer
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6) # 实例化该类
# Sets the callable application as the WSGI application that will receive requests
httpd.set_app(wsgi_handler) # 设置客服务端的处理handler, 即application
httpd.serve_forever()
如上,我们可以看到:在创建WSGIServer实例的时候会指定HTTP请求的Handler,上述代码使用WSGIRequestHandler。当用户的HTTP请求到达服务器时,WSGIServer会创建WSGIRequestHandler实例,使用其handler方法来处理HTTP请求(其实最终是调用wsgiref.handlers.BaseHandler中的run方法处理)。WSGIServer通过set_app方法设置一个可调用(callable)的对象作为application,上面提到的handler方法最终会调用设置的application处理request,并返回response。
其中,WSGIServer继承自wsgiref.simple_server.WSGIServer,而WSGIRequestHandler继承自wsgiref.simple_server.WSGIRequestHandler,wsgiref是Python标准库给出的WSGI的参考实现。
class WSGIServer(HTTPServer): # WSGIServer继承自HTTPServer,HTTPServer继承自TCPServer
"""BaseHTTPServer that implements the Python WSGI protocol"""
application = None
def server_bind(self):
"""Override server_bind to store the server name."""
HTTPServer.server_bind(self)
self.setup_environ()
def setup_environ(self): # 设置env环境参数
# Set up base environment
env = self.base_environ = {}
env['SERVER_NAME'] = self.server_name
env['GATEWAY_INTERFACE'] = 'CGI/1.1'
env['SERVER_PORT'] = str(self.server_port)
env['REMOTE_HOST']=''
env['CONTENT_LENGTH']=''
env['SCRIPT_NAME'] = ''
def get_app(self): # 获得处理器handler
return self.application
def set_app(self,application): # 设置处理器handler
self.application = application
二、处理Request
第一步中说到的application,即为django.core.management.commands.runserver中的get_handler()方法
def get_internal_wsgi_application():
"""
Loads and returns the WSGI application as configured by the user in
``settings.WSGI_APPLICATION``. With the default ``startproject`` layout,
this will be the ``application`` object in ``projectname/wsgi.py``.
This function, and the ``WSGI_APPLICATION`` setting itself, are only useful
for Django's internal server (runserver); external WSGI servers should just
be configured to point to the correct application object directly.
If settings.WSGI_APPLICATION is not set (is ``None``), we just return
whatever ``django.core.wsgi.get_wsgi_application`` returns.
"""
from django.conf import settings # 加载生成project时生成的setting文件
app_path = getattr(settings, 'WSGI_APPLICATION') # 检查settings配置文件中是否设置“WSGI_APPLICATION”
if app_path is None: # 如果没有设置,就使用默认的application
return get_wsgi_application()
try:
return import_string(app_path) # 如果有设置,就返回设置的application
except ImportError as e:
msg = (
"WSGI application '%(app_path)s' could not be loaded; "
"Error importing module: '%(exception)s'" % ({
'app_path': app_path,
'exception': e,
})
)
six.reraise(ImproperlyConfigured, ImproperlyConfigured(msg),
sys.exc_info()[2])
当settings文件中未设置WSGI_APPLICATION,就会使用django默认的内部wsgi方法,其中,get_wsgi_application()方法就是调用此方法,该函数在django.core.wsgi.py文件中
def get_wsgi_application():
"""
The public interface to Django's WSGI support. Should return a WSGI
callable.
Allows us to avoid making django.core.handlers.WSGIHandler public API, in
case the internal WSGI implementation changes or moves in the future.
"""
django.setup(set_prefix=False) # 加载django初始环境
return WSGIHandler() # 返回WSGI处理器
此方法在加载django处理化环境后,返回一个WSGIHandler类,下面我们看看这个处理器中的代码
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest # 调用WSGIResquest对象
def __init__(self, *args, **kwargs):
super(WSGIHandler, self).__init__(*args, **kwargs)
self.load_middleware() # 加载所有的中间件
def __call__(self, environ, start_response): # 类实例化调用此方法
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, environ=environ)