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 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM