zoukankan      html  css  js  c++  java
  • 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',
    
  • 相关阅读:
    学 Win32 汇编[28]
    C#将数据集DataSet中的数据导出到EXCEL文件的几种方法
    FFmpeg 学习(四):FFmpeg API 介绍与通用 API 分析
    Android 代码混淆配置总结
    Android 视频播放器 (三):使用NBPlayer播放直播视频
    Android 视频播放器 (二):使用MediaPlayer播放视频
    Android 展示控件之Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系
    Android 视频播放器 (一):使用VideoView播放视频
    JavaCV 学习(二):使用 JavaCV + FFmpeg 制作拉流播放器
    Android Studio 常见问题及解决方法
  • 原文地址:https://www.cnblogs.com/Franciszw/p/13552269.html
Copyright © 2011-2022 走看看