81 lines
3.6 KiB
Python
81 lines
3.6 KiB
Python
# /opt/1panel/apps/openresty/nginx/www/sites/43.142.166.152.443/django/utils/exception_handler.py
|
||
|
||
from rest_framework.views import exception_handler
|
||
from rest_framework.response import Response
|
||
from rest_framework import status
|
||
import logging
|
||
import os
|
||
|
||
logger = logging.getLogger('django')
|
||
|
||
def custom_exception_handler(exc, context):
|
||
"""
|
||
生产环境安全异常处理器 - 不泄露任何敏感信息
|
||
基于你之前项目的代码,做了小优化
|
||
"""
|
||
# 先调用默认异常处理器
|
||
response = exception_handler(exc, context)
|
||
|
||
if response is not None:
|
||
# 🔥 记录原始错误信息到日志(便于排查)
|
||
request = context['request']
|
||
user_info = f"用户: {request.user.id if request.user.is_authenticated else '未登录'}"
|
||
logger.error(
|
||
f"API异常 - 路径: {request.path}, "
|
||
f"方法: {request.method}, {user_info}, "
|
||
f"状态码: {response.status_code}, 错误: {str(exc)}"
|
||
)
|
||
|
||
# 🔥 生产环境返回标准化错误,不暴露任何细节
|
||
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': '网关超时'},
|
||
}
|
||
|
||
# 🔥 如果是调试模式,返回详细错误(便于开发)
|
||
from django.conf import settings
|
||
if settings.DEBUG:
|
||
return response
|
||
|
||
# 🔥 生产环境返回标准错误
|
||
standard_response = error_messages.get(
|
||
response.status_code,
|
||
{'code': response.status_code, 'message': '请求错误'}
|
||
)
|
||
|
||
return Response(standard_response, status=response.status_code)
|
||
|
||
# 对于非DRF异常(response为None),生产环境返回通用错误信息
|
||
if response is None:
|
||
from django.conf import settings
|
||
request = context.get('request')
|
||
user_info = '未知'
|
||
if request:
|
||
user_info = f"用户: {request.user.id if request.user.is_authenticated else '未登录'}"
|
||
logger.error(
|
||
f"未处理异常 - 路径: {request.path if request else '未知'}, "
|
||
f"方法: {request.method if request else '未知'}, {user_info}, "
|
||
f"错误类型: {type(exc).__name__}, 错误: {str(exc)}"
|
||
)
|
||
if not settings.DEBUG:
|
||
import traceback
|
||
print(traceback.format_exc())
|
||
return Response(
|
||
{'code': 500, 'message': '服务器内部错误,请稍后重试'},
|
||
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||
)
|
||
return Response(
|
||
{'code': 500, 'message': str(exc)},
|
||
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||
)
|
||
|
||
return response |