翼度科技»论坛 编程开发 python 查看内容

DRF请求的生命周期:三年程序员的实战感悟

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
前言:作为工作一个3年左右的码农,在各种框架的摸爬滚打中,我也接触了不少前端后端的技术栈,其中 Django REST Framework(DRF)算是我后端日常工作中的用得最多的框架。今天就简单聊聊DRF请求的生命周期。从请求的发起,到数据的处理,再到最终的响应返回,每一步都有着很多的细节和挑战,由于篇幅原因,我在此篇文章中只是稍作解析,点到为止。
drf中请求的生命周期:

1、django接收请求后,先进行中间件的process_request方法,进行路由匹配后再进行中间件的process_view方法;
  1. class MiddlewareMixin:
  2.         # 中间件源码,当有请求进来时,会自动执行中间件的call方法;
  3.         # 一般我们自定义中间件都是重写process_request和process_view方法
  4.         # 从源码中可看出执行顺序:
  5.     def __call__(self, request):
  6.         # Exit out to async mode, if needed
  7.         if asyncio.iscoroutinefunction(self.get_response):
  8.             return self.__acall__(request)
  9.         response = None
  10.         if hasattr(self, 'process_request'):
  11.             response = self.process_request(request)   
  12.         response = response or self.get_response(request)
  13.         if hasattr(self, 'process_response'):
  14.             response = self.process_response(request, response)
  15.         return response
复制代码
2、再执行APIView类中的as_view方法获取view函数,并同时免除了csrf认证(闭包原理)
  1. class APIView(View):
  2.     # 简略版源码:
  3.     @classmethod
  4.     def as_view(cls, **initkwargs):
  5.         view = super().as_view(**initkwargs) # 调用原Django框架的as_view方法获取view函数
  6.         view.cls = cls
  7.         view.initkwargs = initkwargs
  8.         return csrf_exempt(view)
  9. # 原Django框架的as_view方法:
  10. class View:
  11.     @classonlymethod
  12.     def as_view(cls, **initkwargs):
  13.         def view(request, *args, **kwargs):
  14.             self = cls(**initkwargs)
  15.             self.setup(request, *args, **kwargs)
  16.             return self.dispatch(request, *args, **kwargs) # 调用dispatch函数
  17.         view.view_class = cls
  18.         view.view_initkwargs = initkwargs
  19.         return view
复制代码
3、通过路由匹配执行view函数,并在view中调用dispatch函数。
  1. class APIView(View):
  2.     def dispatch(self, request, *args, **kwargs):
  3.         self.args = args
  4.         self.kwargs = kwargs
  5.         # request封装
  6.         request = self.initialize_request(request, *args, **kwargs)
  7.         self.request = request
  8.         self.headers = self.default_response_headers  # deprecate?
  9.         try:  # 捕获异常
  10.             self.initial(request, *args, **kwargs)  # 版本管理、认证。权限、限流组件执行
  11.             if request.method.lower() in self.http_method_names:  # 执行视图函数
  12.                 handler = getattr(self, request.method.lower(),
  13.                                   self.http_method_not_allowed)
  14.             else:
  15.                 handler = self.http_method_not_allowed
  16.             response = handler(request, *args, **kwargs)
  17.         except Exception as exc:
  18.             response = self.handle_exception(exc)
  19.         self.response = self.finalize_response(request, response, *args, **kwargs)
  20.         return self.response
复制代码
4、在dispatch中进行版本管理、request封装、认证、权限、限流处理
  1. # 版本管理
  2.     def initial(self, request, *args, **kwargs):
  3.         self.format_kwarg = self.get_format_suffix(**kwargs)
  4.         version, scheme = self.determine_version(request, *args, **kwargs)  # 执行versioning_class中的determine_version方法,获取version和scheme
  5.         request.version, request.versioning_scheme = version, scheme  # 封装参数到request中
  6.         # Ensure that the incoming request is permitted
  7.         self.perform_authentication(request)
  8.         self.check_permissions(request)
  9.         self.check_throttles(request)
  10. # request封装
  11.     def initialize_request(self, request, *args, **kwargs):
  12.         parser_context = self.get_parser_context(request)
  13.         return Request(
  14.             request,
  15.             parsers=self.get_parsers(),
  16.             authenticators=self.get_authenticators(),
  17.             negotiator=self.get_content_negotiator(),
  18.             parser_context=parser_context
  19.         )
  20. #认证
  21.     def _authenticate(self):
  22.         for authenticator in self.authenticators:
  23.             try:
  24.                 user_auth_tuple = authenticator.authenticate(self) # 执行authenticate方法进行具体的认证流程
  25.             except exceptions.APIException:
  26.                 self._not_authenticated()
  27.                 raise
  28.             if user_auth_tuple is not None:
  29.                 self._authenticator = authenticator
  30.                 self.user, self.auth = user_auth_tuple  # 将返回值进行封装
  31.                 return
  32.         self._not_authenticated()
  33. # 权限
  34.     def check_permissions(self, request):
  35.         for permission in self.get_permissions():
  36.             if not permission.has_permission(request, self):  # 多个权限类中有一个方法为False则报错并抛出异常
  37.                 self.permission_denied(
  38.                     request,
  39.                     message=getattr(permission, 'message', None),
  40.                     code=getattr(permission, 'code', None)
  41.                 )
  42. # 限流
  43.     def check_throttles(self, request):
  44.         throttle_durations = []
  45.         for throttle in self.get_throttles(): # 循环执行各限流类中的方法
  46.             if not throttle.allow_request(request, self):
  47.                 throttle_durations.append(throttle.wait()) # 限流方法返回False则将等待时间加到列表中
  48.         if throttle_durations:
  49.             durations = [
  50.                 duration for duration in throttle_durations
  51.                 if duration is not None
  52.             ]
  53.             duration = max(durations, default=None) # 取列表中的最大等待时间
  54.             self.throttled(request, duration)  # 抛出异常
复制代码
5、执行具体的视图函数并返回数据

6、执行中间件的process_response方法并返回数据到客户端

以上只是简单分析了一下执行流程,涉及到的源码都是为了方便理解而经过简化的,只供参考。每个组件源码的设计思路和执行流程其实都有一定的复杂度,对于各个组件的源码,我在接下来的日子中也会逐一进行详细剖析。

来源:https://www.cnblogs.com/harry6/p/18438720
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具