我有点束缚......想要我的蛋糕并且也吃它。
我想记录应用程序抛出的所有异常。因此,如果某人遇到错误的URL,我想将堆栈跟踪记录到SLF4J。
所以你可能正在思考,嘿,这很容易,只需实现异常映射并记录异常。"所以我做了:
public class RestExceptionMapper implements ExceptionMapper<java.lang.Exception> {
private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class);
/**
* {@inheritDoc}
*/
@Override
public Response toResponse(Exception exception) {
log.error("toResponse() caught exception", exception);
return null;
}
}
如果你这样做,当有人输入错误的URL时,而不是404错误,他们会得到500错误。人们会猜测返回null会将异常传播到链式处理程序之下,但Jersey并没有这样做。它实际上提供了很少的信息,为什么它会选择一个处理程序而不是另一个...
有没有人遇到过这个问题,你是怎么解决的?
答案 0 :(得分:30)
您可以使用RequestEventListener侦听异常事件并记录throwable,而不会干扰任何现有处理。请注意,这意味着首先注册ApplicationEventListener
,然后返回RequestEventListener
的实例。
public class ExceptionLogger implements ApplicationEventListener, RequestEventListener {
private static final Logger log = LoggerFactory.getLogger(RequestExceptionLogger.class);
@Override
public void onEvent(final ApplicationEvent applicationEvent) {
}
@Override
public RequestEventListener onRequest(final RequestEvent requestEvent) {
return this;
}
@Override
public void onEvent(RequestEvent paramRequestEvent) {
if(paramRequestEvent.getType() == Type.ON_EXCEPTION) {
log.error("", paramRequestEvent.getException());
}
}
}
答案 1 :(得分:7)
要返回正确的http状态代码,您的异常映射器可能如下所示:
@Provider
public class RestExceptionMapper implements ExceptionMapper<Throwable>
{
private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class);
@Override
public Response toResponse(Throwable exception)
{
log.error("toResponse() caught exception", exception);
return Response.status(getStatusCode(exception))
.entity(getEntity(exception))
.build();
}
/*
* Get appropriate HTTP status code for an exception.
*/
private int getStatusCode(Throwable exception)
{
if (exception instanceof WebApplicationException)
{
return ((WebApplicationException)exception).getResponse().getStatus();
}
return Response.Status.INTERNAL_SERVER_ERROR.getStatusCode();
}
/*
* Get response body for an exception.
*/
private Object getEntity(Throwable exception)
{
// return stack trace for debugging (probably don't want this in prod...)
StringWriter errorMsg = new StringWriter();
exception.printStackTrace(new PrintWriter(errorMsg));
return errorMsg.toString();
}
}
此外,您似乎对级联异常映射器感兴趣,但根据规范,这是不可能的:
JAX-RS 2.0规范,第4.4章
“异常映射提供程序将已检查或运行时异常映射到Response实例。一个异常 映射提供程序实现ExceptionMapper接口,可以使用注释 @Provider用于自动发现。选择异常映射提供程序来映射异常时, 实现必须使用其泛型类型是异常的最近超类的提供者。
当资源类或提供程序方法抛出异常映射的异常时 provider,匹配提供程序用于获取Response实例。生成的响应将被处理 好像Web资源方法已经返回响应,请参见第3.3.3节。特别是映射 必须使用第6章中定义的ContainerResponse过滤器链处理响应。
为了避免潜在的无限循环,在处理a期间必须使用单个异常映射器 请求及其相应的响应。 JAX-RS实现绝不能尝试映射异常 在处理先前从异常映射的响应时抛出。相反,这个例外必须 按照第3.3.4节中的步骤3和4所述进行处理。“