Django 源码阅读:url解析

Posted Mr_扛扛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django 源码阅读:url解析相关的知识,希望对你有一定的参考价值。

一、写在前面

继上一篇博文,进一步分析Django URL解析过程。通过网上博客的学习以及对于源码阅读所做笔记。

邮箱地址:jpzhang.ht@gmail.com
个人博客:https://jianpengzhang.github.io/
CSDN博客:http://blog.csdn.net/u011521019

二、写在前面

上一篇博文,django.core.servers.basehttp.py run()函数,服务启动最后的动作是httpd.serve_forever,调用的是socketserver.BaseServer.serve_forever方法。该方法采用了selector网络模型进行等待数据。启动服务后服务器进入一个无限循环的状态,poll_interval用来设置循环间隔时间,默认为0.5秒。在这里先简单分析下Python SocketServer.py 源码,上篇博文中这块的介绍没有好好的梳理。在这里进行补充下。

/usr/lib/python2.7/SocketServer.py:BaseServer.serve_forever()

class BaseServer:
    timeout = None
    def __init__(self, server_address, RequestHandlerClass):
        # 初始化,传入构建一个Socket服务器所必需的address以及每个请求到达时的处理类
        """Constructor.  May be extended, do not override."""
        self.server_address = server_address
        # RequestHandlerClass 注册 handle 函数,在finish_request 中实例化,调用用户定义的 handle 函数
        self.RequestHandlerClass = RequestHandlerClass
        self.__is_shut_down = threading.Event()
        self.__shutdown_request = False
        
    def server_activate(self):
        """Called by constructor to activate the server.
    
        May be overridden.
          服务器激活,由构造函数调用以激活服务器。可能被重写。
        """
        pass
        
    
    # 装饰器函数,重新启动被eintr中断的系统调用
    def _eintr_retry(func, *args):
        """restart a system call interrupted by EINTR"""
        while True:
            try:
                return func(*args)
            except (OSError, select.error) as e:
                if e.args[0] != errno.EINTR:
                    raise
    
    
    def serve_forever(self, poll_interval=0.5):
        """Handle one request at a time until shutdown.
    
        Polls for shutdown every poll_interval seconds. Ignores
        self.timeout. If you need to do periodic tasks, do them in
        another thread.
        """
        self.__is_shut_down.clear()
        try:
            while not self.__shutdown_request:
                # XXX: Consider using another file descriptor or
                # connecting to the socket to wake this up instead of
                # polling. Polling reduces our responsiveness to a
                # shutdown request and wastes cpu at all other times.
                # 调用 select 监视请求,处理 EINTR 异常
                r, w, e = _eintr_retry(select.select, [self], [], [],
                                       poll_interval)
                if self in r:
                 # 有请求进来
                    self._handle_request_noblock()
        finally:
            self.__shutdown_request = False
            self.__is_shut_down.set()
    … …         

SocketServer.py中的 BaseServer 和 BaseRequestHandler
Python为网络编程提高了更高级的封装。SocketServer.py 提供了不少网络服务的类。它们的设计很优雅。Python把网络服务抽象成两个主要的类,一个是Server类,用于处理连接相关的网络操作,另外一个则是RequestHandler类,用于处理数据相关的操作。并且提供两个MixIn 类,用于扩展 Server,实现多进程或多线程。在构建网络服务的时候,Server 和 RequestHandler 并不是分开的,RequestHandler的实例对象在Server 内配合 Server工作。
主要几个Server关系如下:

+------------+
| BaseServer |
+------------+
      |
      v
+-----------+        +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+        +------------------+
      |
      v
+-----------+        +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+        +--------------------+

BaseServer 分析

BaseServer 通过__init__初始化,对外提供serve_forever和 handler_request方法,在这里初始化动作是在django.core.servers.basehttp.py run()函数中httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)触发,其中httpd_cls是通过type()函数动态加载的WSGIServer类,这里httpd_cls表示:<class 'django.core.servers.basehttp.WSGIServer'>,继承自:<class 'django.core.servers.basehttp.WSGIServer'>,socketserver.ThreadingMixIn

init 初始化:

def __init__(self, server_address, RequestHandlerClass):
    # 初始化,传入构建一个Socket服务器所必需的address以及每个请求到达时的处理类
    """Constructor.  May be extended, do not override."""
    self.server_address = server_address
    # RequestHandlerClass 注册 handle 函数,在finish_request 中实例化,调用用户定义的 handle 函数
    self.RequestHandlerClass = RequestHandlerClass
    self.__is_shut_down = threading.Event()
    self.__shutdown_request = False

__init__源码很简单。主要作用是创建server对象,并初始化server地址和处理请求的class。熟悉socket编程应该很清楚,server_address是一个包含主机和端口的元组。

serve_forever
创建了server对象之后,使用server对象开启一个无限循环。

def serve_forever(self, poll_interval=0.5):
    """Handle one request at a time until shutdown.

    Polls for shutdown every poll_interval seconds. Ignores
    self.timeout. If you need to do periodic tasks, do them in
    another thread.
    """
    self.__is_shut_down.clear()
    try:
        while not self.__shutdown_request:
            # XXX: Consider using another file descriptor or
            # connecting to the socket to wake this up instead of
            # polling. Polling reduces our responsiveness to a
            # shutdown request and wastes cpu at all other times.
            # 调用 select 监视请求,处理 EINTR 异常
            r, w, e = _eintr_retry(select.select, [self], [], [],
                                   poll_interval)
            if self in r:
                # 有请求进来
                self._handle_request_noblock()
    finally:
        self.__shutdown_request = False
        self.__is_shut_down.set()

serve_forever接受一个参数poll_interval,用于表示select轮询的时间。然后进入一个无限循环,调用select方式进行网络IO的监听。
如果select函数返回,表示有IO连接或数据,那么将会调用_handle_request_noblock方法。

_handle_request_noblock

def _handle_request_noblock(self):
    """Handle one request, without blocking.

    I assume that select.select has returned that the socket is
    readable before this function was called, so there should be
    no risk of blocking in get_request().
    处理一个请求,不会阻塞。 我假设select.select返回了在调用此函数之前套接字是可读的,因此get_request()中不应存在阻塞的风险。
    """
    try:
        # 接收请求 accept,get_request 由子类实现,一般为接收请求,返回 socket
        request, client_address = self.get_request()
    except socket.error:
        return
    if self.verify_request(request, client_address):
        try:
            # BaseServer.process_request 中有 BaseRequestHandler 的回调动作,实例化用户定义的 handler, __init__ 中完成对 handle() 的调用
            self.process_request(request, client_address)
        except:
            self.handle_error(request, client_address)
            # 关闭连接
            self.shutdown_request(request)
    else:
        self.shutdown_request(request)

_handle_request_noblock方法即开始处理一个请求,并且是非阻塞。该方法通过get_request方法获取连接,具体的实现在其子类。一旦得到了连接,调用verify_request方法验证请求。验证通过,即调用process_request处理请求。如果中途出现错误,则调用handle_error处理错误,以及shutdown_request结束连接。

get_request

在这里,调用的是子类class TCPServer(BaseServer)中的get_request。TCPServer 继承了BaseServer,初始化的时候,进行了socket套接字的创建。

get_request:
该类最重要的方法就是 get_request。该方法进行返回socket对象的请求连接。

def get_request(self):
    """Get the request and client address from the socket.

    May be overridden.
    从套接字获取请求和客户端地址。可以覆盖。
    """
    return self.socket.accept()

get_request方法是在BaseServer基类中的_handle_request_noblock中调用,从那里里传入套接字对象获取的连接信息。如果是UDPServer,这里获取的就是UDP连接。
此外,TCPServer还提供了一个 fileno 方法,提供给基类的select调用返回文件描述符。

verify_request

def verify_request(self, request, client_address):
    """Verify the request.  May be overridden.

    Return True if we should proceed with this request.
    验证请求。 可以覆盖。如果我们应该继续这个请求,则返回True。
    """
    return True

该方法对request进行验证,通常会被子类重写。简单的返回True即可,然后进入process_request方法处理请求。

process_request
在这里调用的是在ThreadingMixIn类定义的process_request函数,并不是BaseServer类中的process_request。

class ThreadingMixIn:
    """Mix-in class to handle each request in a new thread.用于处理新线程中的每个请求的混合类。"""

    # Decides how threads will act upon termination of the
    # main process
    # 决定线程在主进程终止时的操作方式
    daemon_threads = False

    def process_request_thread(self, request, client_address):
        """Same as in BaseServer but as a thread.

        In addition, exception handling is done here.
            与BaseServer相同,但这里作为线程。此外,此处完成异常处理。
        """
        try:
            self.finish_request(request, client_address)
            self.shutdown_request(request)
        except:
            self.handle_error(request, client_address)
            self.shutdown_request(request)

    def process_request(self, request, client_address):
        """Start a new thread to process the request.启动一个新线程来处理请求"""
        t = threading.Thread(target = self.process_request_thread,
                             args = (request, client_address))
        t.daemon = self.daemon_threads
        t.start()

process_request方法是mixin的入口,MixIn子类通过重写该方法,进行多线程或多进程的配置。调用finish_request完成请求的处理,同时调用shutdown_request结束请求。

finish_request

def finish_request(self, request, client_address):
    """Finish one request by instantiating RequestHandlerClass.
    通过实例化RequestHandlerClass完成一个请求。
    """
    self.RequestHandlerClass(request, client_address, self)

finish_request方法将会处理完毕请求。创建RequestHandlerClass对象,并通过RequestHandlerClass做具体的处理。

其中self.RequestHandlerClass(request, client_address, self):在_init_()中定义为self.RequestHandlerClass = RequestHandlerClass

在这里,RequestHandlerClass参数是上一博文中,在:
django.core.servers.basehttp.py run()函数(1)中定义的WSGIRequestHandler类,在(2)中进行初始化,既调用BaseServer中的_init_()。

def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
    server_address = (addr, port)
    if threading:
        httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, server_cls), ) # (1)这里,动态加载类,这里httpd_cls:<class 'django.core.servers.basehttp.WSGIServer'>,继承自:<class 'django.core.servers.basehttp.WSGIServer'>,socketserver.ThreadingMixIn
    else:
        httpd_cls = server_cls
    httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6) #(2)这里,参数WSGIRequestHandler:<class 'django.core.servers.basehttp.WSGIRequestHandler'>
   … …

因此,RequestHandlerClass是由django.core.servers.basehttp.py: def run() -> httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)传递过来的参数WSGIRequestHandler:django.core.servers.basehttp.WSGIRequestHandler。

也就是说当执行self.RequestHandler(request, client_address, self)时等同于执行django.core.servers.basehttp.WSGIRequestHandler(request, client_address, self)

WSGIRequestHandler
django.core.servers.basehttp.WSGIRequestHandler(request, client_address, self)
在这里,初始化WSGIRequestHandler的时候可以看到并没有__init__()函数,查看继承关系,
django.core.servers.basehttp.WSGIRequestHandler ->
simple_server.WSGIRequestHandler ->
BaseHTTPServer.BaseHTTPRequestHandler ->
SocketServer.StreamRequestHandler ->
SocketServer.BaseRequestHandler
在这里即调用BaseRequestHandler类_init_ 完成对 handle() 的调用。

BaseRequestHandler 分析
所有requestHandler都继承BaseRequestHandler基类。

class BaseRequestHandler:
    def __init__(self, request, client_address, server):
        self.request = request # 客户端请求对象,<class 'socket._socketobject'>
        self.client_address = client_address # 客户端地址,('192.168.31.178', 50029)
        self.server = server # 服务端
        self.setup() # 调用子类的setup()函数,处理socket连接
        try:
            self.handle()
        finally:
            self.finish()

    def setup(self):
        pass

    def handle(self):
        pass

    def finish(self):
        pass

BaseRequestHandler是请求处理程序类的基类,该类会处理每一个请求。

_init_()为每个要处理的请求实例化该类。 初始化对象的时候,设置请求request对象、client_address和server,然后调用setup方法,子类会重写该方法,用于处理socket连接,接下来的将是handler和finish方法。 要实现特定服务,需要做的就是派生一个定义handle()方法的类。所有对请求的处理,都可以重写handler方法。
可以简单的理解为:setup()是处理前的初始化操作,handle()是处理请求,finish()是清理操作。

setup(self)

设置完请求request对象、client_address和server后,接着执行self.setup(),该函数在子类StreamRequestHandler实现。

StreamRequestHandler。它继承了BaseRequestHandler。基类的setup方法和finish方法被它重写,用于通过连接实现缓存文件的读写操作。

class StreamRequestHandler(BaseRequestHandler):
    """
    rfile、wfile的默认缓冲区大小。我们默认将rfile设为buffered,否则对于大数据(每个字节的getc()调用)会很慢;我们将wfile设为无缓冲,因为(a)通常在写入()之后,我们想要读取并且需要刷新该行;(b)对未缓冲文件的大写入通常由stdio优化。
    """
     # 为流式套接字定义rfile和wfile
    rbufsize = -1
    wbufsize = 0
    
    # 应用于请求套接字的超时(如果不是None)。
    timeout = None
    
     # 如果为True,则禁用此套接字的nagle算法。
     # 仅在wbufsize!= 0时使用,以避免小数据包。
    disable_nagle_algorithm = False

    def setup(self):
        self.connection = self.request
        if self.timeout is not None:
            self.connection.settimeout(self.timeout)
        if self.disable_nagle_algorithm:
            self.connection.setsockopt(socket.IPPROTO_TCP,
                                       socket.TCP_NODELAY, True)
        self.rfile = self.connection.makefile('rb', self.rbufsize) # 一个类似文件的对象,可以用来接收客户端的数据
        self.wfile = self.connection.makefile('wb', self.wbufsize) # 一个类似文件的对象,可以向客户端返回数据

    def finish(self):
        if not self.wfile.closed:
            try:
                self.wfile.flush()
            except socket.error:
                # 此处可能发生最终套接字错误,例如本地错误ECONNABORTED。
                pass
        self.wfile.close()
        self.rfile.close()

setup

setup判断了是否使用nagle算法。然后设置对应的连接属性。最重要的就是创建了一个可读(rfile)和一个可写(wfile)的“文件”对象,他们实际上并不是创建了文件,而是封装了读取数据和发送数据的操作,抽象成为对文件的操作。可以理解为 self.rfile 就是读取客户端数据的对象,它有一些方法可以读取数据。self.wfile则是用来发送数据给客户端的对象。后面的操作,客户端数据到来会被写入缓冲区可读,需要向客户端发送数据的时候,只需要向可写的文件中write数据即可。

finish
在finish()中清理了对应的文件对象,同时wfile关闭之前需要刷新,将一些没有向客户端返回数据数据返回掉。

def finish(self):
    if not self.wfile.closed:
        # wfile关闭之前需要刷新
        try:
            self.wfile.flush()
        except socket.error:
            pass
    self.wfile.close()
    self.rfile.close()

handle()
django.core.servers.basehttp.handle()

handle(),调用子类django.core.servers.basehttp.WSGIRequestHandler中的handle()函数,主要处理的是HTTP是否保持连接的问题,如果保持连接就持续处理客户请求,否则就结束,最后使用shutdown来关闭socket的功能。
handle_one_request()比较重要语句:

def handle(self):
    self.close_connection = True
    self.handle_one_request()
    while not self.close_connection:
        # 连接没有关闭,循环处理每一个请求
        self.handle_one_request()
    try:
        """
        使用shutdown来关闭socket的功能
        SHUT_RDWR:关闭读写,即不能使用send/write/recv/read等
        SHUT_RD:关闭读,即不能使用read/recv等
        SHUT_WR:关闭写功能,即不能使用send/write等
        除此之外,还将缓冲区中的内容清空
        """
        self.connection.shutdown(socket.SHUT_WR)
    except (socket.error, AttributeError):
        pass

handle_one_request()

def handle_one_request(self):
    """Copy of WSGIRequestHandler.handle() but with different ServerHandler
    WSGIRequestHandler.handle()的副本,但具有不同的ServerHandler
    """
    # 读取第一行raw_requestline,一般格式应该是:COMMAND PATH VERSION\\r\\n;解析请求。这里:'GET /i18n/js/horizon+openstack_dashboard/ HTTP/1.1\\r\\n'

    self.raw_requestline = self.rfile.readline(65537)
    if len(self.raw_requestline) > 65536:
        # 如果解析的请求地址长度大于65536个字节,发送和记录一个414错误回复给client。
        self.requestline = ''
        self.request_version = ''
        self.command = ''
        self.send_error(414)
        return
    # 解析请求(内部)。请求应存储在self.raw_requestline中; 结果在self.command,self.path,self.request_version和self.headers中。
    # 返回True表示成功,False表示失败; 失败时,会发回错误。
    if not self.parse_request():
        return
    # 初始化一个服务器处理程序,初始化动作在父类中实现
    # ServerHandler() ->
    # django.core.servers.basehttp.ServerHandler()->
    # wsgiref.simple_server.ServerHandler() ->
    # wsgiref.handlers.SimpleHandler().__init__()
    # python重定向sys.stdin、sys.stdout和sys.stderr:标准输入、标准输出和错误输出
    # handler:<django.core.servers.basehttp.ServerHandler object at 0x7fca4bdc64d0>
    handler = ServerHandler(
        self.rfile, self.wfile, self.get_stderr(), self.get_environ()
    )
    # self:<django.core.servers.basehttp.WSGIRequestHandler object at 0x7fee45763550>
    handler.request_handler = self      # backpointer for logging & connection closing 用于记录和连接关闭的backpointer
    handler.run(self.server.get_app())

其中,self.parse_request(),既调用父类中的BaseHTTPServer.BaseHTTPRequestHandler.parse_request
(),解析请求(内部)。需要解析的请求存储在self.raw_requestline中; 结果在self.command,self.path,self.request_version和self.headers中。返回True表示成功,False表示失败; 失败时,会发回错误。
command:是一个(区分大小写)关键字,如GET或POST。
path:是一个包含请求的路径信息的字符串。应该是字符串“HTTP / 1.0”或“HTTP / 1.1”。使用URL编码方案进行编码(使用%xx表示带有十六进制代码xx的ASCII字符。
request_version:包括请求的HTTP协议版本号的字符串,样例:‘HTTP/1.0’。
headers:headers是包含头信息的mimetools.Message(或派生类)的实例;

HTTP 请求(request)
http 请求分为三个部分:
1. 第一行:请求类型、地址和版本号
2. 头部信息:HTTP header
3. 数据部分
标准的 HTTP 请求是:

GET / HTTP/1.1
Host: cizixs.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
If-Modified-Since: Thu, 25 Feb 2016 16:00:57 GMT
Cache-Control: max-age=0

标准的 HTTP 响应头部:

HTTP/1.1 304 Not Modified
Server: GitHub.com
Date: Thu, 24 Mar 2016 06:21:25 GMT
Last-Modified: Thu, 25 Feb 2016 16:00:57 GMT
access-control-allow-origin: *
Expires: Thu, 24 Mar 2016 06:31:25 GMT
Cache-Control: max-age=600
X-GitHub-Request-Id: 3AF60A59:7CE3:1C889201:56F38765
 
data...

parse_request()

def parse_request(self)
    self.command = None  # set in case of error on the first line
    # 默认请求版本。这只会影响响应,直到请求行被解析为止,因此它主要决定客户端在发送请求格式错误时返回什么。大多数web服务器默认为HTTP 0.9,即不发送状态行。
    self.request_version = version = self.default_request_version
    # 关闭连接设置为真
    self.close_connection = 1
    # 原始请求行
    requestline = self.raw_requestline
    # 删除 requestline 字符串末尾的指定字符,这里表示换行
    requestline = requestline.rstrip('\\r\\n')
    self.requestline = requestline
    # 默认一空格分割请求行
    words = requestline.split()
    if len(words) == 3:
        command, path, version = words
        if version[:5] != 'HTTP/':
            # 如果请求版本不是HTTP/开头,则返回400
            self.send_error(400, "Bad request version (%r)" % version)
            return False
        try:
            # 例如version=HTTP/1.1,则返回1.1
            base_version_number = version.split('/', 1)[1]
            # 返回['1', '1']
            version_number = base_version_number.split(".")
            # RFC 2145 3.1节规定只能有一个'.' 和主要和次要数字必须被视为单独的整数;
            if len(version_number) != 2:
                # 如果包含版本好的数字少于两个则抛出异常
                raise ValueError
            # 类型转换(1, 1)    
            version_number = int(version_number[0]), int(version_number[1])
        except (ValueError, IndexError):
            self.send_error(400, "Bad request version (%r)" % version)
            return False
        # 如果版本好大于等于(1, 1),以及支持的HTTP协议版本大于等于"HTTP/1.1",则表示请求的版本号正确,关闭连接设置为假。
        if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
            self.close_connection = 0
        if version_number >= (2, 0):
            self.send_error(505,
                      "Invalid HTTP Version (%s)" % base_version_number)
            return False
    elif len(words) == 2:
        # 请求第一行2个,即“请求类型”、“地址”和“版本号”中缺少一个,则返回400错误。
        command, path = words
        self.close_connection = 1
        if command != 'GET':
            self.send_error(400,
                            "Bad HTTP/0.9 request type (%r)" % command)
            return False
    elif not words:
        return False
    else:
        self.send_error(400, "Bad request syntax (%r)" % requestline)
        return False
    # 如果http请求第一行为:GET / HTTP/1.1,则:self.command=GET, self.path=/, self.request_version=HTTP/1.1
    self.command, self.path, self.request_version = command, path, version

    # 检查标题并查找连接指令
    self.headers = self.MessageClass(self.rfile, 0)
    # 请求头中查找“Connection: keep-alive”
    conntype = self.headers.get('Connection', "")
    if conntype.lower() == 'close':
        # 关闭请求连接
        self.close_connection = 1
    elif (conntype.lower() == 'keep-alive' and
          self.protocol_version >= "HTTP/1.1"):
          # 保持请求连接
        self.close_connection = 0
    return True

handle_one_request()最后执行到handler.run(self.server.get_app())
这里包含两个动作:self.server.get_app()、handler.run()

self.server.get_app(),/usr/lib/python2.7/wsgiref/simple_server.py:WSGIServer().get_app()

def get_app(self):
    # <django.contrib.staticfiles.handlers.StaticFilesHandler object at 0x7fee45834c10>
    return self.application

返回一个StaticFilesHandler类对象,继承WSGIHandler,它的目的是为了判断每个请求,如果是常规的url请求则直接分配到某个view中去执行,如果是静态文件规则那么将不会找view而是响应这个文件。
这里请求的地址为:/i18n/js/horizon+openstack_dashboard/看上去是一个静态文件。

handler.run(),/usr/lib/python2.7/wsgiref/handlers.py(76):BaseHandler.run()

def run(self, application):
    """Invoke the application调用应用程序"""
    try:
        # 为一个请求设置环境,包括输入、错误输出。
        self.setup_environ()
        # 调用:/usr/local/lib/python2.7/dist-packages/django/contrib/staticfiles/handlers.py(62)__call__()
        self.result = application(self.environ, self.start_response)
        # 发送任何可迭代数据,然后关闭self和iterable
        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.

self.result = application(self.environ, self.start_response) ->
/usr/local/lib/python2.7/dist-packages/django/contrib/staticfiles/handlers.py(62)StaticFilesHandler(WSGIHandler)
.call() ->
/usr/local/lib/python2.7/dist-packages/django/core/handlers/wsgi.py(153)WSGIHandler(base.BaseHandler).call()

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)# 调用WSGIRequest实例化请求
    response = self.get_response(request) # 调用处理方法处理request,返回给定HttpRequest的HttpResponse对象

    response._handler_class = self.__class__# 设置_handler_class 为当前处理的类

    status = '%d %s' % (response.status_code, response.reason_phrase)# 相应结果的状态码和对应描述
    # 获取响应的响应头部信息,获取响应的cookie信息
    response_headers = [
        *response.items(),
        *(('Set-Cookie', c.output(header='')) for c in response.cookies.values()),
    ]
    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# 返回处理结果

调用处理方法处理request,返回给定HttpRequest的HttpResponse对象。

def get_response(self, request):
    """Return an HttpResponse object for the given HttpRequest.返回给定HttpRequest的HttpResponse对象。"""
    # Setup default url resolver for this thread为此线程设置默认URL解析程序
    set_urlconf(settings.ROOT_URLCONF)# 设置url配置
    # 调用settings.MIDDLEWARE中配置的中间件进行处理,
    response = self._middleware_chain(request)
    response._closable_objects.append(request)
    if response.status_code >= 400:
        log_response(
            '%s: %s', response.reason_phrase, request.path,
            response=response,
            request=request,
        )
    return response

至此,简单的分析完成,后续随着自己的理解将进一步补充说明。

以上是关于Django 源码阅读:url解析的主要内容,如果未能解决你的问题,请参考以下文章

Django 第二十五篇Django admin源码解析

DRF之APIView源码解析

CVB生命周期(APIView源码解析)

django类视图简单使用和源码解析

(十二)Geospark源码解析(一)

如何阅读 URL 末尾的#2? [复制]