每当引发异常时,它们都会记录在控制台中(如果使用了 Sentry,则记录在 Sentry 中)。
其中许多例外仅旨在向用户显示。例如,django-graphql-jwt
引发PermissionDenied
login_required
装饰器异常。
问题是这会在测试/开发期间污染控制台输出,并在生产期间将有效错误记录到 Sentry。对于上述示例等例外情况,这仅旨在向用户显示,而不是记录。
作为一种解决方法,我尝试编写中间件来捕获任何抛出的异常:
class ExceptionFilterMiddleware:
IGNORED_EXCEPTIONS = (
# Local exceptions
ValidationException,
# Third-party exceptions
JSONWebTokenExpired,
PermissionDenied,
)
def on_error(self, error):
if not isinstance(error, self.IGNORED_EXCEPTIONS):
return error
def resolve(self, next, *args, **kwargs):
return next(*args, **kwargs).catch(self.on_error)
但是,如果异常被捕获或未返回,它将不再填充errors
查询/变异输出中的字段。因此记录所有错误,没有办法有条件地记录异常。
这意味着唯一的解决方案是创建一个日志过滤器,如下所示:
def skip_valid_exceptions(record):
"""
Skip exceptions for errors only intended to be displayed to the API user.
"""
skip: bool = False
if record.exc_info:
exc_type, exc_value = record.exc_info[:2]
skip = isinstance(exc_value, valid_exceptions)
return not skip
record.exc_info
但这也不起作用,因为None
每当 Graphene 抛出错误时,因此无法根据异常类型有条件地过滤掉异常。
有解决方案吗?这似乎是一个常见问题,但我找不到任何解决方案。
或者,我不能使用异常向 API 用户显示错误,但这意味着将错误放入查询结果的data.errors
字段而不是errors
. 这是一个标准,需要适配前端逻辑(比如 Apollo 的错误处理),并不理想。这也意味着无法从引发异常的第三方库(如 django-graphql-jwt)中使用任何功能。