别摸我
别摸我
文章目录
  1. Django源码分析(四) – HTTP请求过程
    1. 1、再来看 run() 方法

Django源码分析(三)--HTTP请求到响应过程分析

Django源码分析(四) – HTTP请求过程

所有 Web 框架都是一样, 处理 http 请求: 接收 request, 返回 response

前面我们介绍了:

  • 加载project settings
  • 创建WSGIServer

不管是 runserver 方式还是 uWSGI 启动 Django 项目, 在启动时都会调用 django.core.servers.basehttp 中的 run() 方法, 创建一个 django.core.servers.WSGIServer 的实例, 之后调用 server_forever() 方法启动HTTP服务, 一直处理请求到服务被关闭。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# socketserver.py
class BaseServer:
...
def serve_forever(self, poll_interval=0.5):
self.__is_shut_down.clear()
try:
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)

while not self.__shutdown_request:
ready = selector.select(poll_interval)
if ready:
self._handle_request_noblock()

self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()

def _handle_request_noblock(self):
try:
request, client_address = self.get_request()
except OSError:
return
if self.verify_request(request, client_address):
try:
self.process_request(request, client_address)
except Exception:
self.handle_error(request, client_address)
self.shutdown_request(request)
except:
self.shutdown_request(request)
raise
else:
self.shutdown_request(request)

从源码中可以看到, while 循环一直调用 _handle_request_noblock 方法去处理请求。 _handle_request_noblock 方法处理请求要经过四个过程: get_request、verify_request、process_request、shutdown_request

1、再来看 run() 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
# django\core\servers\basehttp.py

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()

可以看到创建 WSGIServer 实例时传进 WSGIRequestHandler 参数, 然后 set_app 方法设置一个可调用的对象作为 application, 请求最终将由这个 application 对象处理并返回 response

当收到 HTTP 请求时, WSGIServer 会为每一个请求实例化一个 WSGIRequestHandler 对象, 而 WSGIRequestHandler类 继承自 BaseRequestHandler:

1
2
3
4
5
6
7
8
9
10
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()

可以看到, 实际是用 WSGIRequestHandlerhandle() 方法来处理请求(其实最终是使用 wsgiref.handlers.BaseHandler 中的 run 方法处理), 来看看 handle() 里做的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class WSGIRequestHandler(simple_server.WSGIRequestHandler):
def handle(self):
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

if not self.parse_request(): # An error code has been sent, just exit
return

handler = ServerHandler(
self.rfile, self.wfile, self.get_stderr(), self.get_environ()
)
handler.request_handler = self # backpointer for logging
handler.run(self.server.get_app())

handler 实例化了一个 ServerHandler对象, 并把之前设置的 application 作为参数传入它的 run 方法中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class BaseHandler:      # WSGIRequestHandler 继承于 BaseHandler
def run(self, application):
"""Invoke the application"""
try:
self.setup_environ()
self.result = application(self.environ, self.start_response)
self.finish_response()
except:
try:
self.handle_error()
except:
# If we get an error handling an error, just give up already!
self.close()
raise # ...and let the actual server figure it out.

这里就调用了

1
2

## 2、处理```Request

前面说到的 application , 在 Django 中一般是 django.core.handlers.wsgi.WSGIHandler 对象, WSGIHandler 继承自 django.core.handlers.base.BaseHandler ,
这是 Django 处理 Request 的核心, 它会创建一个 WSGIRequest 实例, 而 WSGIRequesthttp.HttpRequest 继承而来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# django\core\handlers\wsgi.py
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest

def __init__(self, *args, **kwargs):
super().__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)
request = self.request_class(environ)
response = self.get_response(request)

response._handler_class = self.__class__

status = '%d %s' % (response.status_code, response.reason_phrase)
response_headers = list(response.items())
for c in response.cookies.values():
response_headers.append(('Set-Cookie', c.output(header='')))
start_response(status, response_headers)
if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
response = environ['wsgi.file_wrapper'](response.file_to_stream)
return response

支持一下
扫一扫,支持heaven
  • 微信扫一扫
  • 支付宝扫一扫