zoukankan      html  css  js  c++  java
  • django 异常处理中间件

    3.1 Djang 对 request 的处理

    以本地开发为例,当浏览器发起一次请求时,Django 中的 wsgi 创建一个 WSGIHandler 对象处理请求。在
    WSGIHandler 对象中初始化环境变量,如果没有异常,则调用 self.get_response(request) 函数处理请求,返回 response 给 wsgi。

    get_response 定义在 django.core.handlers.base.py 文件中,下面是处理流程。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    	for middleware_method in self._request_middleware:
    		response = middleware_method(request)
    		if response:
    			break
    	...
    	if response is None:
    	...
    		for middleware_method in self._view_middleware:
    			response = middleware_method(request, callback, callback_args, callback_kwargs)
    			if response:
    				break
    	...
    	response = wrapped_callback(request, *callback_args, **callback_kwargs)
    	...
    	if response is None:
    		try:
    			response = wrapped_callback(request, *callback_args, **callback_kwargs)
    		except Exception as e:
    			for middleware_method in self._exception_middleware:
    				response = middleware_method(request, e)
    				if response:
    					break
    			if response is None:
    				raise
    	...
    	for middleware_method in self._response_middleware:
    		response = middleware_method(request, response)
    	...
    	return response
    

    这张图能比较好的呈现整个处理流程逻辑.

    3.2 ExceptionBox

    Django 的中间件支持一种 Exception 的写法。当发生未捕获处理的异常时,执行中间件中定义的函数 process_exception,如果返回一个 response, 那么就可以结束整个流程。

    在 Django 工程中,需要一个异常处理和错误码统一管理的模块。于是便有了 ExceptionBox。

    数据的返回格式:

    {
    	'code': '404',
    	'message': '错误提示XXXX',
    	'result': False,
    	'data': None
    }
    

      

    代码实例演示:

    简介

    django-exceptionbox 是一个 Django 的异常处理工具包。

    将 HTTP 状态码封装成 Python 异常 Base 类,使用 raise 抛出异常,通过 Django 中间件,统一处理异常,打印日志。

    通过继承 base.py 中的异常类,可以实现对异常的封装。

    需要注意的是,返回的错误码是类名,是一个短语。这样处理的目的是为了前后端更易于理解和使用。

    下载包之后,需要重命名为 exceptionbox。

    配置

    添加中间件 'exceptionbox.middleware.ExceptionBoxMiddleware' 到 settings中

    MIDDLEWARE_CLASSES = (
        'exceptionbox.middleware.ExceptionBoxMiddleware',
        ...
    )

    中间件的位置没有特殊要求

    使用

    第一步

    在 exceptionbox/error.py 文件,继承 base.py 中的异常类,实现业务逻辑相关的异常类。

    例如:

    class ERROR_LOGIN_FRONT_PAY_NOT_MONEY(base.PreconditionFailed412):
        message = "没有足够余额"

    第二步

    在 views.py 文件中,抛出异常。

    import exceptionbox
    
    
    def my_view(request):
        raise exceptionbox.ERROR_LOGIN_FRONT_PAY_NOT_MONEY()

    接口返回

    status_code = 412

    {
        "message": "没有足够余额",
        "code": "ERROR_LOGIN_FRONT_PAY_NOT_MONEY",
        "data": null,
        "result": false
    }

    base.py

    from abc import ABCMeta
    
    
    class BaseReturn(Exception):
        __metaclass__ = ABCMeta
    
    
    # 1XX Informational
    class Continue100(BaseReturn):
        status_code = 100
    
    
    class SwitchingProtocols101(BaseReturn):
        status_code = 101
    
    
    class Processing102(BaseReturn):
        status_code = 102
    
    
    # 2XX Success
    class OK200(BaseReturn):
        status_code = 200
    
    
    class Created201(BaseReturn):
        status_code = 201
    
    
    class Accepted202(BaseReturn):
        status_code = 202
    
    
    class NonAuthoritativeInformation203(BaseReturn):
        status_code = 203
    
    
    class NoContent204(BaseReturn):
        status_code = 204
    
    
    class ResetContent205(BaseReturn):
        status_code = 205
    
    
    class PartialContent206(BaseReturn):
        status_code = 206
    
    
    class MultiStatus207(BaseReturn):
        status_code = 207
    
    
    class AlreadyReported208(BaseReturn):
        status_code = 208
    
    
    class IMUsed226(BaseReturn):
        status_code = 226
    
    
    # 3XX Redirection
    class MultipleChoices300(BaseReturn):
        status_code = 300
    
    
    class MovedPermanently301(BaseReturn):
        status_code = 301
    
    
    class Found302(BaseReturn):
        status_code = 302
    
    
    class SeeOther303(BaseReturn):
        status_code = 303
    
    
    class NotModified304(BaseReturn):
        status_code = 304
    
    
    class UseProxy305(BaseReturn):
        status_code = 305
    
    
    class TemporaryRedirect307(BaseReturn):
        status_code = 307
    
    
    class PermanentRedirect308(BaseReturn):
        status_code = 308
    
    
    class Accepted202(BaseReturn):
        status_code = 202
    
    
    # 4XX Client Error
    class BadRequest400(BaseReturn):
        status_code = 400
    
    
    class Unauthorized401(BaseReturn):
        status_code = 401
    
    
    class PaymentRequired402(BaseReturn):
        status_code = 402
    
    
    class Forbidden403(BaseReturn):
        status_code = 403
    
    
    class NotFound404(BaseReturn):
        status_code = 404
    
    
    class MethodNotAllowed405(BaseReturn):
        status_code = 405
    
    
    class NotAcceptable406(BaseReturn):
        status_code = 406
    
    
    class ProxyAuthenticationRequired407(BaseReturn):
        status_code = 407
    
    
    class RequestTimeout408(BaseReturn):
        status_code = 408
    
    
    class Conflict409(BaseReturn):
        status_code = 409
    
    
    class Gone410(BaseReturn):
        status_code = 410
    
    
    class LengthRequired411(BaseReturn):
        status_code = 411
    
    
    class PreconditionFailed412(BaseReturn):
        status_code = 412
    
    
    class PayloadTooLarge413(BaseReturn):
        status_code = 413
    
    
    class RequestURITooLong414(BaseReturn):
        status_code = 414
    
    
    class UnsupportedMediaType415(BaseReturn):
        status_code = 415
    
    
    class RequestedRangeNotSatisfiable416(BaseReturn):
        status_code = 416
    
    
    class ExpectationFailed417(BaseReturn):
        status_code = 417
    
    
    class IMATeapot418(BaseReturn):
        status_code = 418
    
    
    class MisdirectedRequest421(BaseReturn):
        status_code = 421
    
    
    class UnprocessableEntity422(BaseReturn):
        status_code = 422
    
    
    class Locked423(BaseReturn):
        status_code = 423
    
    
    class FailedDependency424(BaseReturn):
        status_code = 424
    
    
    class UpgradeRequired426(BaseReturn):
        status_code = 426
    
    
    class PreconditionRequired428(BaseReturn):
        status_code = 428
    
    
    class TooManyRequests429(BaseReturn):
        status_code = 429
    
    
    class PreconditionRequired428(BaseReturn):
        status_code = 428
    
    
    class RequestHeaderFieldsTooLarge431(BaseReturn):
        status_code = 431
    
    
    class ConnectionClosedWithoutResponse444(BaseReturn):
        status_code = 444
    
    
    class UnavailableForLegalReasons451(BaseReturn):
        status_code = 451
    
    
    class ClientClosedRequest499(BaseReturn):
        status_code = 499
    
    
    # 5XX Server Error
    
    class InternalServerError500(BaseReturn):
        status_code = 500
    
    
    class NotImplemented501(BaseReturn):
        status_code = 501
    
    
    class BadGateway502(BaseReturn):
        status_code = 502
    
    
    class ServiceUnavailable503(BaseReturn):
        status_code = 503
    
    
    class GatewayTimeout504(BaseReturn):
        status_code = 504
    
    
    class HTTPVersionNotSupported505(BaseReturn):
        status_code = 505
    
    
    class VariantAlsoNegotiates506(BaseReturn):
        status_code = 506
    
    
    class InsufficientStorage507(BaseReturn):
        status_code = 507
    
    
    class LoopDetected508(BaseReturn):
        status_code = 508
    
    
    class NotExtended510(BaseReturn):
        status_code = 510
    
    
    class NetworkAuthenticationRequired511(BaseReturn):
        status_code = 511
    
    
    class NetworkConnectTimeoutError599(BaseReturn):
        status_code = 599
    © 2021 GitHub, Inc.
    

     

    error.py

    from __future__ import unicode_literals
    from . import base
    
    
    class ERROR_LOGIN_FRONT_NOT_GIFT(base.PreconditionFailed412):
        message = u"礼品不充足"
    
    
    class ERROR_LOGIN_FRONT_PAY_NOT_MONEY(base.PreconditionFailed412):
        message = u"没有足够余额"
    
    
    class ERROR_FAULT(base.ServiceUnavailable503):
        message = u"服务器内部错误"
    

     

    middiareware.py

    # -*- coding: utf-8 -*-
    import json
    import logging
    import traceback

    from django.http import JsonResponse

    from .base import BaseReturn

    logger = logging.getLogger('root')


    class ExceptionBoxMiddleware(object):
    def __init__(self, get_response):
    self.get_response = get_response

    def __call__(self, request):
    return self.get_response(request)
    def process_exception(self, request, exception):
    if not issubclass(exception.__class__, BaseReturn):
    return None
    ret_json = {
    'code': exception.__class__.__name__,
    'message': getattr(exception, 'message', ''),
    'success': False,
    'data': []
    }
    response = JsonResponse(ret_json)
    response.status_code = getattr(exception, 'status_code', 500)
    _logger = logger.error if response.status_code >= 500 else logger.warning
    _logger('status_code->{status_code}, error_code->{code}, url->{url}, '
    'method->{method}, param->{param}, '
    'traceback->{traceback}'.format(
    status_code=response.status_code, code=ret_json['code'], url=request.path,
    method=request.method, param=json.dumps(getattr(request, request.method, {})),
    traceback=traceback.format_exc()
    ))
    return response

     

    源代码地址:middiareware原作者的代码有bug按照我的代码替换

    https://github.com/shaowenchen/django-exceptionbox/issues 

  • 相关阅读:
    UITextView in iOS7 doesn't scroll
    interlliJ idea 不识别文件类型的解决方式
    __super
    自用广告过滤规则,整合xwhyc大大的,非常小才79K
    Eclipse设置打印线
    SQL Server批量替换全部表中内容sql语句-清楚挂马
    删除同样元素(线性表)
    学习node js 之微信公众帐号接口开发 准备工作之三
    Bitmap基本概念及在Android4.4系统上使用BitmapFactory的注意事项
    多个rs485设备怎样跟上位机通讯?
  • 原文地址:https://www.cnblogs.com/SunshineKimi/p/14327290.html
Copyright © 2011-2022 走看看