学习Django的时候知道,在Django请求的生命周期中,请求经过WSGI和中间件到达路由,不管是FBV还是CBV都会先执行View视图函数中的dispatch方法

REST framework是基于Django的API框架,REST framework采用的是CBV的请求模式.

所以在一个项目中,使用了REST framework的时候,

请求到达REST framework后,也先执行REST framework中的dispatch方法

先来看看dispatch方法的源码

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

查看initialize_request方法,可以知道这个方法接收客户端的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
)

再查看Request方法的源码

可以知道这个Request类是rest framework中定义的一个类

class Request(object):

	def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
self._request = request
self.parsers = parsers or ()
self.authenticators = authenticators or ()
self.negotiator = negotiator or self._default_negotiator()
self.parser_context = parser_context
self._data = Empty
self._files = Empty
self._full_data = Empty
self._content_type = Empty
self._stream = Empty if self.parser_context is None:
self.parser_context = {}
self.parser_context['request'] = self
self.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSET force_user = getattr(request, '_force_auth_user', None)
force_token = getattr(request, '_force_auth_token', None)
if force_user is not None or force_token is not None:
forced_auth = ForcedAuthentication(force_user, force_token)
self.authenticators = (forced_auth,)

先不看这个Request到底执行了什么操作

但是已经知道经过Request处理过的request已经不再是客户端发送过来的那个request了

initialize_request方法中,有一个方法处理过request,来看看get_parser_context方法的源码

def get_parser_context(self, http_request):

    return {
'view': self,
'args': getattr(self, 'args', ()),
'kwargs': getattr(self, 'kwargs', {})
}

在这里,view的值是self,代指的是UsersView这个对象,所以get_parser_context方法把UsersView这个类封装进来然后返回

所以get_parser_context方法最后返回的当前对象以及当前对象所传的参数

经过initialize_request函数处理之后的request,现在就变成了

Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)

现在再来看看Request的其他参数代指的是什么

get_parsers					根据字面意思,是解析get请求的意思
get_authenticators 认证相关
get_content_negotiator 选择相关
parser_context 封闭self和self的参数 def get_parsers(self): return [parser() for parser in self.parser_classes] def get_authenticators(self): return [auth() for auth in self.authentication_classes] def get_permissions(self): return [permission() for permission in self.permission_classes] def get_throttles(self): return [throttle() for throttle in self.throttle_classes] def get_content_negotiator(self): if not getattr(self, '_negotiator', None):
self._negotiator = self.content_negotiation_class()
return self._negotiator

再来看看UsersView这个类中的get方法和post方法

def get(self,request,*args,**kwargs):
pass def post(self,request,*args,**kwargs):
pass

可以看到get方法的参数中有一个request,通过前面可以知道这个request已经不是最开始时到达服务端的request了

这个request方法中已经被REST framework封装了解析,认证和选择等相关的方法

def dispatch(self, request, *args, **kwargs):

    self.args = args
self.kwargs = kwargs
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

default_response_headers这个方法从它的注释可以看出已经被丢弃了.

再来看initial这个方法

def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg # Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)

先执行get_format_suffix来获取客户端所发送的url的后缀

然后执行perform_content_negotiation方法,从它的注释可以知道这个方法的主要作用是执行内容选择,并把服务端接收到的信息保存在request中

然后再执行determine_version方法

def determine_version(self, request, *args, **kwargs):
"""
If versioning is being used, then determine any API version for the
incoming request. Returns a two-tuple of (version, versioning_scheme)
"""
if self.versioning_class is None:
return (None, None)
scheme = self.versioning_class()
return (scheme.determine_version(request, *args, **kwargs), scheme)

determine_version方法的官方注释中可以知道,determine_version方法的主要作用是

如果url中有版本信息,就获取发送到服务端的版本,返回一个元组

执行完上面的方法,再执行perform_authentication方法来进行认证操作

来看下perform_authentication方法的源码

def perform_authentication(self, request):
"""
Perform authentication on the incoming request. Note that if you override this and simply 'pass', then authentication
will instead be performed lazily, the first time either
`request.user` or `request.auth` is accessed.
"""
request.user

从上面有代码及注释中可以看出,perform_authentication方法的作用就是

执行认证功能,确认进行后续操作的用户是被允许的.
perform_authentication方法返回经过认证的用户对象

执行完perform_authentication方法,就会执行check_permissions方法

def check_permissions(self, request):
"""
Check if the request should be permitted.
Raises an appropriate exception if the request is not permitted.
"""
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request, message=getattr(permission, 'message', None)
)

check_permissions方法的作用是

如果用户通过认证,检查用户是否有权限访问url中所传的路径.
如用用户访问的是没有没有权限的路径,则会抛出异常.

check_permissions方法执行完成后,就会执行check_throttles方法

check_throttles方法的作用是检查用户是否被限制了访问主机的次数

如果用户访问服务器的次数超出设定值,则会抛出一个异常

例如,如果想限制一个ip地址每秒钟只能访问几次,一个小时之内最多可以访问多少次,就可以在settings.py文件中进行配置

def check_throttles(self, request):
"""
Check if request should be throttled.
Raises an appropriate exception if the request is throttled.
"""
for throttle in self.get_throttles():
if not throttle.allow_request(request, self):
self.throttled(request, throttle.wait())

initial这个方法执行完成后,request.method.lower把请求的方法转换成小写

# Get the appropriate handler method
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)

再通过通过反射的方式来执行UsersView类中的get或post等自定义方法

需要注意的是,在执行initial方法之前,使用了try/except方法来进行异常处理

如果执行initial方法的时候出现错误,就调用handle_exception来处理initial方法抛出的异常,返回正确的响应信息

def handle_exception(self, exc):
"""
Handle any exception that occurs, by returning an appropriate response,
or re-raising the error.
"""
if isinstance(exc, (exceptions.NotAuthenticated,
exceptions.AuthenticationFailed)):
# WWW-Authenticate header for 401 responses, else coerce to 403
auth_header = self.get_authenticate_header(self.request) if auth_header:
exc.auth_header = auth_header
else:
exc.status_code = status.HTTP_403_FORBIDDEN exception_handler = self.get_exception_handler() context = self.get_exception_handler_context()
response = exception_handler(exc, context) if response is None:
self.raise_uncaught_exception(exc) response.exception = True
return response

在前面,如果initial方法执行完成没有抛出异常,则根据反射执行自定义的请求方法,然后返回响应信息

如果initial方法抛出异常则执行handle_exception方法处理抛出的异常,也返回响应信息

等到上面的过程执行完成后,再执行finalize_response方法把最终的响应信息返回给客户端的浏览器

def finalize_response(self, request, response, *args, **kwargs):
"""
Returns the final response object.
"""
# Make the error obvious if a proper response is not returned
assert isinstance(response, HttpResponseBase), (
'Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` '
'to be returned from the view, but received a `%s`'
% type(response)
) if isinstance(response, Response):
if not getattr(request, 'accepted_renderer', None):
neg = self.perform_content_negotiation(request, force=True)
request.accepted_renderer, request.accepted_media_type = neg response.accepted_renderer = request.accepted_renderer
response.accepted_media_type = request.accepted_media_type
response.renderer_context = self.get_renderer_context() # Add new vary headers to the response instead of overwriting.
vary_headers = self.headers.pop('Vary', None)
if vary_headers is not None:
patch_vary_headers(response, cc_delim_re.split(vary_headers)) for key, value in self.headers.items():
response[key] = value return response

所以总结:

REST framework请求的生命周期为:

1.请求到达服务端,经过WSGI和中间件到达路由系统
2.路由系统执行配置的CBV或者FBV中的dispatch方法
3.在dispatch方法中,request方法被封装添加了解析器,认证方法及选择器等方法
4.然后执行initial方法
5.再获取版本,进行认证操作,权限操作和节流操作
6.最后执行自定义的get,post,push,delete等自定义方法
7.在执行initial方法之前,通过try来捕获可能出现的异常
8.如果出现异常,就执行handle_exception方法来处理捕获到的异常
9.不管是否出现异常,最后的返回值都通过finalize_response方法来处理响应的内容

源码剖析Django REST framework的请求生命周期的更多相关文章

  1. 源码剖析Django REST framework的认证方式及自定义认证

    源码剖析Django REST framework的认证方式 在前面说过,请求到达REST framework的时候,会对request进行二次封装,在封装的过程中会对客户端发送过来的request封 ...

  2. springMVC源码阅读-通过画图理解一个请求生命周期(十二)

  3. SpringMVC源码剖析(四)- DispatcherServlet请求转发的实现

    SpringMVC完成初始化流程之后,就进入Servlet标准生命周期的第二个阶段,即“service”阶段.在“service”阶段中,每一次Http请求到来,容器都会启动一个请求线程,通过serv ...

  4. Django(十一)请求生命周期之响应内容(请求/响应 头/体)

    https://www.cnblogs.com/renpingsheng/p/7534897.html Django请求生命周期之响应内容 http提交数据的方式有"post",& ...

  5. 深入剖析PHP7内核源码(一)- PHP架构与生命周期

    PHP7 为什么这么快? 全新的zval 更节约的空间,栈上分配内存 zend_string 存储字符串的Hash值,数组查询的时候不需要进行Hash计算 在HashTable桶内直接存数据,减少了内 ...

  6. Django(十一)请求生命周期之CBV与FBV

    https://www.cnblogs.com/yuanchenqi/articles/8715364.html FBV FBV(function base views) 就是在视图里使用函数处理请求 ...

  7. ASP.NET Core 源码阅读笔记(2) ---Microsoft.Extensions.DependencyInjection生命周期管理

    在上一篇文章中我们主要分析了ASP.NET Core默认依赖注入容器的存储和解析,这一篇文章主要补充一下上一篇文章忽略的一些细节:有关服务回收的问题,即服务的生命周期问题.有关源码可以去GitHub上 ...

  8. Tomcat 源码分析(一)——启动与生命周期组件

    写在前面的话:读Tomcat源码也有段时间了,大领悟谈不上.一些小心得记录下来,供大家参考相护学习. 一.启动流程 Tomcat启动首先需要熟悉的是它的启动流程.和初学者第一天开始写Hello Wor ...

  9. VueJs 源码分析 ---(二)实力化生命周期,以及解析模版和监听数据变化

    Vue 源码第二步 当前 Vue 的版本 V2.2.2 生命周期 相关介绍 我们可以从 setp1 中 去看到那张 vue 的生命周期图中看到,vue 的生命周期钩子. 具体的钩子时干什么的? 以及在 ...

随机推荐

  1. python 基础大纲

    机器语言: 特点:计算机能够看懂的0和1去写程序 优点:程序运行速度快 缺点:开发效率低 汇编语言: 特点:用一些英文标签代替一串而精致数字去写程序 优点:比机器语言好一点,操作系统内大量使用汇编语言 ...

  2. 三、Spring的面向切面

    Spring的面向切面 在应用开发中,有很多类似日志.安全和事务管理的功能.这些功能都有一个共同点,那就是很多个对象都需要这些功能.复用这些通用的功能的最简单的方法就是继承或者委托.但是当应用规模达到 ...

  3. CSS样式之表格,表单

    布局样式 .container:固定宽度并具响应式 .container-fluid自由宽度(100%宽度) 标题样式 <h1>到<h6> 样式已经写好了,可以直接用,兼容性也 ...

  4. JAVA基础知识总结:六

    一.不定长参数 1.语法:数据类型... 变量名称 使用注意事项:a.不定长参数就相当于是一个数组 b.不定长参数只能出现在参数列表的最后面 c.一个函数的参数列表中只能出现一次不定长参数 d.对于不 ...

  5. yii2布局选择与属性标签设置

    Yii选择布局的方法: 1. 通过控制器成员变量设置: public $layout = false;//不使用布局 public $layout = 'main';//设置使用的布局文件(@app/ ...

  6. 机器学习技法:06 Support Vector Regression

    Roadmap Kernel Ridge Regression Support Vector Regression Primal Support Vector Regression Dual Summ ...

  7. 浅析Entity Framework Core中的并发处理

    前言 Entity Framework Core 2.0更新也已经有一段时间了,园子里也有不少的文章.. 本文主要是浅析一下Entity Framework Core的并发处理方式. 1.常见的并发处 ...

  8. 使用angular4和asp.net core 2 web api做个练习项目(二), 这部分都是angular

    上一篇: http://www.cnblogs.com/cgzl/p/7755801.html 完成client.service.ts: import { Injectable } from '@an ...

  9. C#读写Shapefile

    Shapefile文件是ArcGIS存储矢量要素的标准格式,要读写Shapefile最简单的方法当然是基于ArcObject(或者ArcEngine)开发,不过网上也有一些开源的解译Shapefile ...

  10. FastDFS 集群 安装 配置

    这篇文章介绍如何搭建FastDFS 集群 FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的 ...