泽西岛...如何记录所有异常,但仍调用 ExceptionMappers
我有点困...想要我的蛋糕,也吃掉它.
I'm in a little bit of bind... want my cake and to eat it too.
我想记录我的应用程序抛出的所有个异常.因此,如果有人点击了错误的 URL,我想将堆栈跟踪记录到 SLF4J.
I want to log all exceptions my application throws. So if someone hits an incorrect URL, i want to log the stack trace to SLF4J.
所以你可能在想,'嘿,这很简单,只需实现一个异常映射器并记录异常.所以我做到了:
So you're probably thinking, 'hey thats easy, just implement an exceptionmapper and log the exception." So I did:
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 不会这样做.它实际上提供的信息很少,为什么它会选择一个处理程序而不是另一个处理程序......
If you do this, instead of 404 errors when someone types a wrong URL in, they get a 500 error. One would guess returning null would propagate the exception down the chain handlers, but Jersey doesn't do that. It actually provides very little info why it would choose one handler over another...
有没有人遇到过这个问题,你是怎么解决的?
Has anyone ran into this problem and how did you solve it?
推荐答案
要返回正确的 http 状态代码,您的异常映射器可能如下所示:
To return the correct http status code, your exception mapper could look something like this:
@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();
}
}
听起来您对级联异常映射器感兴趣,但根据规范这是不可能的:
Also it sounds like you are interested in cascading exception mappers, but according to the spec this isn't possible:
JAX-RS 2.0 规范,第 4.4 章
"异常映射提供程序将已检查或运行时异常映射到 Response 实例.异常映射提供者实现了 ExceptionMapper 接口并且可以用@Provider 用于自动发现.在选择异常映射提供程序来映射异常时,实现必须使用泛型类型是异常的最近超类的提供者.
"Exception mapping providers map a checked or runtime exception to an instance of Response. An exception mapping provider implements the ExceptionMapper interface and may be annotated with @Provider for automatic discovery. When choosing an exception mapping provider to map an exception, an implementation MUST use the provider whose generic type is the nearest superclass of the exception.
当资源类或提供者方法抛出异常时,存在异常映射provider,匹配的provider用于获取一个Response实例.处理结果响应就像 Web 资源方法返回了响应一样,请参阅第 3.3.3 节.特别是,一个映射必须使用第 6 章中定义的 ContainerResponse 过滤器链来处理响应.
When a resource class or provider method throws an exception for which there is an exception mapping provider, the matching provider is used to obtain a Response instance. The resulting Response is processed as if a web resource method had returned the Response, see Section 3.3.3. In particular, a mapped Response MUST be processed using the ContainerResponse filter chain defined in Chapter 6.
为避免潜在的无限循环,在处理请求及其相应的响应.JAX-RS 实现不得尝试映射异常在处理先前从异常映射的响应时抛出.相反,这个异常必须按照第 3.3.4 节中的步骤 3 和 4 进行处理."
To avoid a potentially infinite loop, a single exception mapper must be used during the processing of a request and its corresponding response. JAX-RS implementations MUST NOT attempt to map exceptions thrown while processing a response previously mapped from an exception. Instead, this exception MUST be processed as described in steps 3 and 4 in Section 3.3.4."
相关文章