Django处理前端请求的流程梳理

初始

在前端请求到达 Django 应用时,首先到达的是 WSGI 接口(Web Server Gateway Interface)。WSGI 是 Python Web 应用和 Web 服务器之间的标准接口,Django 使用它来处理和响应 Web 请求。也就是首先会经过Django 项目中的 wsgi.py 文件

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'drf_learn.settings')

application = get_wsgi_application()

以上代码就是wsgi.py 文件, 在这里完成WSGIHandler的初始化。代码如下:

import django
from django.core.handlers.wsgi import WSGIHandler


def get_wsgi_application():
    """
    The public interface to Django's WSGI support. Return a WSGI callable.

    Avoids making django.core.handlers.WSGIHandler a public API, in case the
    internal WSGI implementation changes or moves in the future.
    Django 的 WSGI 支持的公共接口。返回一个 WSGI 可调用对象。避免将 django.core.handlers.WSGIHandler 设为公共 API,
    以防内部 WSGI 实现在未来发生变化或移动。
    """
    django.setup(set_prefix=False)
    return WSGIHandler()

WSGIHandler类内部,实现了__call__方法,WSGI服务会调用__call__方法。方法如下:

    def __call__(self, environ, start_response):
        """

        :param environ: 一个包含所有请求信息的字典,由 WSGI 服务器传入。
        :param start_response: 一个回调函数,用于开始 HTTP 响应并设置响应状态和头信息
        :return:
        """
        #  # 设置脚本前缀
        # 设置请求的脚本前缀。get_script_name 从 environ 中获取请求的路径前缀(即当前应用的路径前缀,通常在部署在子路径下时有用)。
        # Django 使用 SCRIPT_NAME 环境变量设置脚本前缀,以正确地处理多路径部署情况。
        """
        在很多应用场景中,我们可能需要将一个 Django 应用部署到服务器的某个子路径下,而不是根路径。例如:

        假设你的主域名为 https://example.com
        你的 Django 应用部署在子路径 /myapp/ 下
        客户端访问你的 Django 应用的 URL 是 https://example.com/myapp/
        在这种情况下,Django 需要知道当前的子路径 (/myapp/),以便正确地解析和生成 URL。
        这就是 SCRIPT_NAME 的作用——它告诉 Django 请求的路径前缀是什么,以便应用在生成链接时知道要添加的子路径。
        """
        # get_script_name(environ):从 environ 中读取 SCRIPT_NAME 的值,获取当前请求的路径前缀。在上例中,这个值就是 "/myapp"。
        # set_script_prefix:设置 Django 全局的脚本前缀,使得后续请求中引用的所有 URL 都会以这个前缀开头。
        set_script_prefix(get_script_name(environ))


        # # 发送请求开始信号
        # 发送 request_started 信号,通知所有接收者一个新的请求即将开始。接收者可以是中间件或其他监听这个信号的函数。
        #         # 这在一些自定义逻辑中可能有用,例如日志记录或初始化特定的上下文变量,
        """
            signals.request_started:这是 Django 的 request_started 信号对象。
            send 方法:用于发送信号,触发所有连接到该信号的接收者。
            参数解释:
                sender=self.__class__:指定信号的发送者,这里是 WSGIHandler 类本身。这样接收者可以根据发送者来判断是否处理该信号。
                environ=environ:传递给接收者的附加信息,这里是 WSGI 的环境变量字典 environ,包含了请求的所有信息。
            常见的接收者:
                数据库连接管理:
                    Django 的数据库连接组件会监听 request_started 信号,以确保在请求开始时建立数据库连接,或者重置连接。
                缓存系统:
                    一些缓存机制可能需要在请求开始时进行清理或初始化。
                第三方应用程序:
                    一些中间件或应用程序可能需要在请求开始时执行特定的逻辑,如统计请求数量、日志记录等。
            意义:允许接收者在请求处理的早期阶段执行初始化操作,确保在请求处理过程中所需的资源和环境已准备就绪。
        """
        signals.request_started.send(sender=self.__class__, environ=environ)


        # # 创建 HttpRequest 对象 将 WSGI 的 environ 字典转换为 Django 的 HttpRequest 对象。
        #  这个 HttpRequest 对象包含了所有关于请求的信息(例如路径、请求头、请求方法等),供后续处理使用。
        request = self.request_class(environ)


        # # 获取响应 处理请求,返回 HttpResponse 对象
        """
            2.1 请求处理的核心方法
                self.get_response(request) 是 Django 中处理请求的核心方法,定义在 django.core.handlers.base.BaseHandler 类中。
                它负责从接收到的 HttpRequest 对象出发,经过一系列步骤,最终生成并返回 HttpResponse 对象。
            这个方法会调用 Django 的中间件和视图,处理请求并生成响应。具体步骤如下:
                请求预处理:调用中间件的 process_request 方法。
                URL 解析:根据请求的路径,解析出对应的视图函数或类。
                视图处理:调用视图函数或类,生成响应。
                异常处理:在视图处理过程中捕获异常,进行处理。
                请求后处理:调用中间件的 process_response 方法,对响应进行后续处理。
                返回响应:最终返回一个 HttpResponse 对象。
        """
        response = self.get_response(request)

        response._handler_class = self.__class__

        status = "%d %s" % (response.status_code, response.reason_phrase)
        # 设置响应头
        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"
        ):
            # If `wsgi.file_wrapper` is used the WSGI server does not call
            # .close on the response, but on the file wrapper. Patch it to use
            # response.close instead which takes care of closing all files.
            # 如果使用 'wsgi.file_wrapper',则 WSGI 服务器不会在响应上调用 .close,
            # 而是在文件包装器上调用 .close。将其修补为使用 response.close,它负责关闭所有文件。
            response.file_to_stream.close = response.close
            response = environ["wsgi.file_wrapper"](
                response.file_to_stream, response.block_size
            )
        # 返回相应内容
        return response
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大油头儿

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值