DRF 3 请求响应异常处理

3,请求,响应,异常

3.1 DRF Request

from rest_framework.request import Request

REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。

REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。

Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。

无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。

Request常用属性

1).data

request.data 返回解析之后的请求体数据。类似于Django中标准的request.POSTrequest.FILES属性,但提供如下特性:

  • 包含了解析之后的文件和非文件数据
  • 包含了对POST、PUT、PATCH请求方式解析后的数据
  • 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据

2).query_params

request.query_params与Django标准的request.GET相同,只是更换了更正确的名称而已。

3).请求头的数据

ip地址和token都在http的请求头里

request.META.get('HTTP_REMOTE_ADDR') 取IP地址

request.META.get('HTTP_AUTHORIZATION') 取token

补充:Django源生request的使用

1.获取请求路径中的查询字符串参数,可以通过request.GET属性获取,返回QueryDict对象

2.前端发送的表单类型的请求体数据,可以通过request.POST属性获取,返回QueryDict对象

3.非表单类型的请求体数据,Django无法自动解析,可以通过request.body属性获取原始数据自己处理

4.可以通过request.META属性获取请求头headers中的数据

5.HttpRequest对象的属性GET、POST都是QueryDict类型的对象

​ 方法get():根据键获取值,如果一个键同时拥有多个值将获取最后一个值

​ 方法getlist():根据键获取值,值以列表返回,可以获取指定键的所有值

3.2 DRF Response

from rest_framework.response import Response

REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。

REST framework提供了Renderer 渲染器,用来根据请求头中的Accept(接收数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式。

可以在rest_framework.settings查找所有的drf默认配置项

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
    )
}

使用

Response(data, status=None, template_name=None, headers=None, content_type=None)

data数据不要是render处理之后的数据,只需传递python的内建类型数据即可,REST framework会使用renderer渲染器处理data

data不能是复杂结构的数据,如Django的模型类对象,对于这样的数据我们可以使用Serializer序列化器序列化处理后(转为了Python字典类型)再传递给data参数。

参数说明:

  • data: 前段要展示的数据,def的data格式不友好
  • status: 状态码,给浏览器识别的,浏览器会更据改状态码做出反应,默认200;
  • template_name: 模板名称,如果使用HTMLRenderer 时需指明;
  • headers: 用于存放响应头信息的字典;
  • content_type: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。

Response的常用属性

1).data

传给response对象的序列化后,但尚未render处理的数据

2).status_code

状态码的数字

3).content

经过render处理后的响应数据

状态码

为了方便设置状态码,REST framewrok在rest_framework.status模块中提供了常用状态码常量。

1)信息告知 - 1xx

2)成功 - 2xx

3)重定向 - 3xx

4)客户端错误 - 4xx

5)服务器错误 - 5xx

自定义Response


class APIResponse(Response):
    def __init__(self,code=100,msg='成功',data=None,status=None,headers=None,**kwargs):
        dic = {'code': code, 'msg': msg}
        if  data:
            dic = {'code': code, 'msg': msg,'data':data}
        dic.update(kwargs)
        super().__init__(data=dic, status=status,headers=headers)
        
        
# 自己封装的参数,code,msg,data都会被放进一个字典中,然后将该字典打包传个drf的Response的data      
# code是指自定义的状态码,为了说明用户的操作结果,浏览器不会根据它做出反应,是写在data里的
# status是服务器处理状态码,浏览器会根据该状态码做出反应,一般不需要手动填写

3.3 异常处理

drf源生异常处理

这是drf的settings的配置,若要更改默认配置需要在项目的settings里重新配置.

'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',

源码:

from rest_framework.views import exception_handler
def exception_handler(exc, context):
    if isinstance(exc, Http404):
        exc = exceptions.NotFound()
    elif isinstance(exc, PermissionDenied):
        exc = exceptions.PermissionDenied()

    if isinstance(exc, exceptions.APIException):
        headers = {}
        if getattr(exc, 'auth_header', None):
            headers['WWW-Authenticate'] = exc.auth_header
        if getattr(exc, 'wait', None):
            headers['Retry-After'] = '%d' % exc.wait

        if isinstance(exc.detail, (list, dict)):
            data = exc.detail
        else:
            data = {'detail': exc.detail}

        set_rollback()
        return Response(data, status=exc.status_code, headers=headers)

    return None

前后端分离的项目,如果出现异常,drf能处理的异常非常有限,剩下的全部交由Django处理,但是Django的处理方式非常不友好,返回的不是json格式(这不符合restfull规范),我们要做的就是自定义一个异常处理器捕获这些异常,并返回json格式.

自定义异常处理

作用:

1,捕获其他异常,输出为json格式使其符合restfull规范

2,记录日志

自定义异常

# 自定义异常处理的方法
from rest_framework.views import exception_handler
from rest_framework.response import APIResponse  # 自定义包装的response
from rest_framework import status

def my_exception_handler(exc, context):
    response=exception_handler(exc, context)
    # 两种情况,一个是None,drf没有处理
    #response对象,django处理了,但是处理的不符合咱们的要求

    if not response: #drf没处理的情况,还可以更细力度的捕获异常
        if isinstance(exc, ZeroDivisionError):
            return APIResponse(data={'status': 777, 'msg': "除以0的错误" + str(exc)}, status=status.HTTP_400_BAD_REQUEST)
        return APIResponse(data={'status':999,'msg':str(exc)},status=status.HTTP_400_BAD_REQUEST)
    
    
    else:  # drf处理的异常,我们包装一下格式

        return APIResponse(data={'status':888,'msg':response.data.get('detail')},status=status.HTTP_400_BAD_REQUEST)
    
# 全局配置setting.py
'EXCEPTION_HANDLER': 'app01.app_auth.my_exception_handler',
posted @ 2020-08-24 10:07  Franciszw  阅读(338)  评论(0编辑  收藏  举报