DRF請求的生命週期:三年程式設計師的實戰感悟

harry6發表於2024-10-01

前言:作為工作一個3年左右的碼農,在各種框架的摸爬滾打中,我也接觸了不少前端後端的技術棧,其中 Django REST Framework(DRF)算是我後端日常工作中的用得最多的框架。今天就簡單聊聊DRF請求的生命週期。從請求的發起,到資料的處理,再到最終的響應返回,每一步都有著很多的細節和挑戰,由於篇幅原因,我在此篇文章中只是稍作解析,點到為止。


drf中請求的生命週期:

1、django接收請求後,先進行中介軟體的process_request方法,進行路由匹配後再進行中介軟體的process_view方法;
class MiddlewareMixin:
	# 中介軟體原始碼,當有請求進來時,會自動執行中介軟體的call方法;
	# 一般我們自定義中介軟體都是重寫process_request和process_view方法
	# 從原始碼中可看出執行順序:
    def __call__(self, request):
        # Exit out to async mode, if needed
        if asyncio.iscoroutinefunction(self.get_response):
            return self.__acall__(request)
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)   
        response = response or self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response
2、再執行APIView類中的as_view方法獲取view函式,並同時免除了csrf認證(閉包原理)
class APIView(View):
    # 簡略版原始碼:
    @classmethod
    def as_view(cls, **initkwargs):
        view = super().as_view(**initkwargs) # 呼叫原Django框架的as_view方法獲取view函式
        view.cls = cls
        view.initkwargs = initkwargs
        return csrf_exempt(view)

# 原Django框架的as_view方法:
class View:
    @classonlymethod
    def as_view(cls, **initkwargs):
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            self.setup(request, *args, **kwargs)
            return self.dispatch(request, *args, **kwargs) # 呼叫dispatch函式
        view.view_class = cls
        view.view_initkwargs = initkwargs
        return view

3、透過路由匹配執行view函式,並在view中呼叫dispatch函式。
class APIView(View):
    def dispatch(self, request, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
	# request封裝
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:  # 捕獲異常
            self.initial(request, *args, **kwargs)  # 版本管理、認證。許可權、限流元件執行

            if request.method.lower() in self.http_method_names:  # 執行檢視函式
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
4、在dispatch中進行版本管理、request封裝、認證、許可權、限流處理
# 版本管理
    def initial(self, request, *args, **kwargs):

        self.format_kwarg = self.get_format_suffix(**kwargs)

        version, scheme = self.determine_version(request, *args, **kwargs)  # 執行versioning_class中的determine_version方法,獲取version和scheme
        request.version, request.versioning_scheme = version, scheme  # 封裝引數到request中

        # Ensure that the incoming request is permitted
        self.perform_authentication(request)
        self.check_permissions(request)
        self.check_throttles(request)


# request封裝
    def initialize_request(self, request, *args, **kwargs):
        parser_context = self.get_parser_context(request)
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

#認證
    def _authenticate(self):
        for authenticator in self.authenticators:
            try:
                user_auth_tuple = authenticator.authenticate(self) # 執行authenticate方法進行具體的認證流程
            except exceptions.APIException:
                self._not_authenticated()
                raise

            if user_auth_tuple is not None:
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple  # 將返回值進行封裝
                return

        self._not_authenticated()


# 許可權
    def check_permissions(self, request):
        for permission in self.get_permissions():
            if not permission.has_permission(request, self):  # 多個許可權類中有一個方法為False則報錯並丟擲異常
                self.permission_denied(
                    request,
                    message=getattr(permission, 'message', None),
                    code=getattr(permission, 'code', None)
                )


# 限流
    def check_throttles(self, request):
        throttle_durations = []
        for throttle in self.get_throttles(): # 迴圈執行各限流類中的方法
            if not throttle.allow_request(request, self):
                throttle_durations.append(throttle.wait()) # 限流方法返回False則將等待時間加到列表中

        if throttle_durations:
            durations = [
                duration for duration in throttle_durations
                if duration is not None
            ]

            duration = max(durations, default=None) # 取列表中的最大等待時間
            self.throttled(request, duration)  # 丟擲異常

5、執行具體的檢視函式並返回資料
6、執行中介軟體的process_response方法並返回資料到客戶端

以上只是簡單分析了一下執行流程,涉及到的原始碼都是為了方便理解而經過簡化的,只供參考。每個元件原始碼的設計思路和執行流程其實都有一定的複雜度,對於各個元件的原始碼,我在接下來的日子中也會逐一進行詳細剖析。

相關文章