Files
along_django/utils/exception_handler.py
2026-06-16 13:53:30 +08:00

68 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status
import logging
import traceback
from django.conf import settings
logger = logging.getLogger('django.request')
def custom_exception_handler(exc, context):
"""
统一异常处理所有错误写入终端日志logger生产环境响应不泄露细节。
"""
response = exception_handler(exc, context)
request = context.get('request')
path = getattr(request, 'path', 'unknown')
method = getattr(request, 'method', 'unknown')
user = request.user if request else None
user_info = f"用户: {user.id if user and user.is_authenticated else '未登录'}"
if response is not None:
logger.error(
'API异常 path=%s method=%s %s status=%s error=%s',
path, method, user_info, response.status_code, exc,
exc_info=exc,
)
if settings.DEBUG:
return response
error_messages = {
status.HTTP_400_BAD_REQUEST: {'code': 400, 'message': '请求参数错误'},
status.HTTP_401_UNAUTHORIZED: {'code': 401, 'message': '请先登录'},
status.HTTP_403_FORBIDDEN: {'code': 403, 'message': '权限不足'},
status.HTTP_404_NOT_FOUND: {'code': 404, 'message': '资源不存在'},
status.HTTP_405_METHOD_NOT_ALLOWED: {'code': 405, 'message': '请求方法不允许'},
status.HTTP_408_REQUEST_TIMEOUT: {'code': 408, 'message': '请求超时'},
status.HTTP_429_TOO_MANY_REQUESTS: {'code': 429, 'message': '请求过于频繁'},
status.HTTP_500_INTERNAL_SERVER_ERROR: {'code': 500, 'message': '服务器内部错误'},
status.HTTP_502_BAD_GATEWAY: {'code': 502, 'message': '网关错误'},
status.HTTP_503_SERVICE_UNAVAILABLE: {'code': 503, 'message': '服务暂不可用'},
status.HTTP_504_GATEWAY_TIMEOUT: {'code': 504, 'message': '网关超时'},
}
standard_response = error_messages.get(
response.status_code,
{'code': response.status_code, 'message': '请求错误'},
)
return Response(standard_response, status=response.status_code)
# DRF 未处理的异常数据库字段缺失、AttributeError 等)→ 500 且无日志是常见问题
logger.error(
'未处理API异常 path=%s method=%s %s error=%s traceback=%s',
path,
method,
user_info,
exc,
traceback.format_exc(),
)
if settings.DEBUG:
return Response(
{'code': 500, 'message': str(exc), 'detail': traceback.format_exc()},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)
return Response(
{'code': 500, 'message': '服务器内部错误'},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)