将异常从 CXF 拦截器传播到异常映射器
Propagate exception from CXF interceptor to exception mapper
我有一个流程,在 CXF 客户端上我有 jaxrs-in-interceptor、provider 和 exception mapper。在我的例子中,我通过拦截器捕获了来自客户端的不良响应,然后我想中止 cxf 总线链并抛出错误。不幸的是我做不到,因为在每种情况下,拦截器抛出的异常都只被记录下来,但主要错误(错误的 json 格式)被传播到异常映射器。我想避免异常映射器,但我不知道如何。我正在使用 WebClient 来实现这样的拦截器:
@Component
public class MyInterceptor extends AbstractPhaseInterceptor<Message> {
public MyInterceptor() {
super(POST_STREAM);
}
@Override
public void handleMessage(Message message) throws Fault {
if (message != null) {
//message.getExchange().setOneWay(true);
//message.getExchange().put(Exception.class, new MyException());
//message.getInterceptorChain().abort();
//message.setContent(Exception.class, new MyException());
//Endpoint ep = message.getExchange().get(Endpoint.class);
//message.getInterceptorChain().abort();
//if (ep.getInFaultObserver() != null) {
// ep.getInFaultObserver().onMessage(message);
//}
//throw new WebApplicationException( new MyException());
//message.setContent(Response.class, response);
throw new Fault(new MyException());
}
}
我读到我应该实施 jaxrs-filter,因为拦截器抛出的异常不会传播到异常映射器。由于 WebClient 的实现,在 java 中有什么方法可以做到这一点吗?
S client = create(url, clazz, list(jsonProvider(), providers));
WebClient.getConfig(client).getInInterceptors().add(new MyInterceptor());
我也试过在拦截器上使用不同的阶段,但也没用。
我一直在研究和测试你的问题。问题是 CXF 拦截器抛出的异常逃脱了 JAX-RS 流(CXF 团队的see the answer)
从拦截器生成的 Fault
可以在拦截器本身实现 handleFault
时被捕获
public void handleFault(Message message) {
Exception e = message.getContent(Exception.class);
}
或者实施 FaultListener
并在 CXF 总线上注册它
WebClient.getConfig(client).getBus().getProperties().put("org.apache.cxf.logging.FaultListener",new MyFaultListener());
public class MyFaultListener implements FaultListener{
public boolean faultOccurred(final Exception exception,final String description,final Message message) {
//return false to avoid warning of default CXF logging interceptor
return false;
}
}
但是你不能return拦截器的自定义响应或向客户端响应故障。
我发现实现所需行为的解决方法包括将 Response 替换为自定义对象,该对象可以由您通常的方法调用处理,例如 exceptionMapper
参见 CXF/ JAX-RS : Return Custom response from interceptor
Into Interceptor.handleMessage
检查您需要的条件并创建具有自定义状态和实体的 Response
。在此之后,停止链
public class MyInterceptor extends AbstractPhaseInterceptor<Message> {
public MyInterceptor() {
super(Phase.POST_STREAM);
}
@Override
public void handleMessage(Message message) throws Fault {
if (message != null) {
//check the condition to raise the error
//build the custom Response replacing service call
Response response = Response
.status(Response.Status.BAD_REQUEST)
.entity("custom error")
.build();
message.getExchange().put(Response.class, response);
//abort interceptor chain in you want to stop processing or throw a Fault (catched by handleFault)
//message.getInterceptorChain().abort();
//throw new Fault (new MyException());
}
public void handleFault(Message messageParam) {
}
}
在创建 JAXRS 客户端时添加 ResponseExceptionMapper 作为提供者
providers.add(new ResponseExceptionMapper<WebApplicationException>() {
@Override
public WebApplicationException fromResponse(Response r) {
return new WebApplicationException(r);
}
});
YourService proxy = JAXRSClientFactory.create(url, clazz,providers);
Client client = WebClient.client(proxy);
WebClient.getConfig(client).getInInterceptors().add(new MyInterceptor());
在此之后,如果完成拦截器检查,对 proxy.yourService()
的调用将引发 WebApplicationException
。您可以按需要的方式捕捉或重新抛出
try{
proxy.yourService();
}catch (WebApplicationException e){
}
希望对您有所帮助
我完全同意之前的回答。我的实现看起来像:
@Component
public class ServiceFailureInterceptor extends AbstractPhaseInterceptor<Message> {
private static final Logger LOG = LoggerFactory.getLogger(ServiceFailureInterceptor.class);
public ServiceFailureInterceptor() {
super(PRE_STREAM);
}
@Override
public void handleMessage(Message message) {
if (message != null) {
int responseCode = (int) message.get(Message.RESPONSE_CODE);
LogicException logicException = ErrorMapper.HTTP_STATUS_CODE_MAPPER.get(responseCode);
InputStream is = b2stream(MapperUtils.json().toBytes(logicException));
// clear old message & exchange
Exchange exchange = message.getExchange();
for (Class<?> contentFormat : message.getContentFormats()) {
message.setContent(contentFormat, null);
}
resetOrigInterceptorChain(message);
resetFault(exchange);
message.setContent(InputStream.class, is);
Message outMessage = createOutMessage(exchange, is);
prepareMessage(outMessage);
prepareMessage(message);
}
}
private void prepareMessage(Message message) {
message.put(Message.REQUESTOR_ROLE, true);
message.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
}
private Message createOutMessage(Exchange exchange, InputStream logicException) {
Endpoint ep = exchange.get(Endpoint.class);
Message outMessage = ep != null ? ep.getBinding().createMessage() : new MessageImpl();
outMessage.setContent(InputStream.class, logicException);
exchange.setOutMessage(outMessage);
outMessage.setExchange(exchange);
return outMessage;
}
private void resetFault(Exchange exchange) {
exchange.put(Exception.class, null);
}
private void resetOrigInterceptorChain(Message message) {
InterceptorChain chain = message.getInterceptorChain();
if (chain != null) {
for (Interceptor<?> interceptor : chain) {
chain.remove(interceptor);
}
chain.reset();
}
}
}
手动设置此异常后,我将转到 ExceptionMapper 实现,其中使用我的 LogicException 并构建异常响应。当通过 WebClient 声明为提供程序时,我无法避免异常映射器,因此我决定使用它并稍后重新映射异常。
我有一个流程,在 CXF 客户端上我有 jaxrs-in-interceptor、provider 和 exception mapper。在我的例子中,我通过拦截器捕获了来自客户端的不良响应,然后我想中止 cxf 总线链并抛出错误。不幸的是我做不到,因为在每种情况下,拦截器抛出的异常都只被记录下来,但主要错误(错误的 json 格式)被传播到异常映射器。我想避免异常映射器,但我不知道如何。我正在使用 WebClient 来实现这样的拦截器:
@Component
public class MyInterceptor extends AbstractPhaseInterceptor<Message> {
public MyInterceptor() {
super(POST_STREAM);
}
@Override
public void handleMessage(Message message) throws Fault {
if (message != null) {
//message.getExchange().setOneWay(true);
//message.getExchange().put(Exception.class, new MyException());
//message.getInterceptorChain().abort();
//message.setContent(Exception.class, new MyException());
//Endpoint ep = message.getExchange().get(Endpoint.class);
//message.getInterceptorChain().abort();
//if (ep.getInFaultObserver() != null) {
// ep.getInFaultObserver().onMessage(message);
//}
//throw new WebApplicationException( new MyException());
//message.setContent(Response.class, response);
throw new Fault(new MyException());
}
}
我读到我应该实施 jaxrs-filter,因为拦截器抛出的异常不会传播到异常映射器。由于 WebClient 的实现,在 java 中有什么方法可以做到这一点吗?
S client = create(url, clazz, list(jsonProvider(), providers));
WebClient.getConfig(client).getInInterceptors().add(new MyInterceptor());
我也试过在拦截器上使用不同的阶段,但也没用。
我一直在研究和测试你的问题。问题是 CXF 拦截器抛出的异常逃脱了 JAX-RS 流(CXF 团队的see the answer)
从拦截器生成的 Fault
可以在拦截器本身实现 handleFault
时被捕获
public void handleFault(Message message) {
Exception e = message.getContent(Exception.class);
}
或者实施 FaultListener
并在 CXF 总线上注册它
WebClient.getConfig(client).getBus().getProperties().put("org.apache.cxf.logging.FaultListener",new MyFaultListener());
public class MyFaultListener implements FaultListener{
public boolean faultOccurred(final Exception exception,final String description,final Message message) {
//return false to avoid warning of default CXF logging interceptor
return false;
}
}
但是你不能return拦截器的自定义响应或向客户端响应故障。
我发现实现所需行为的解决方法包括将 Response 替换为自定义对象,该对象可以由您通常的方法调用处理,例如 exceptionMapper 参见 CXF/ JAX-RS : Return Custom response from interceptor
Into Interceptor.handleMessage
检查您需要的条件并创建具有自定义状态和实体的 Response
。在此之后,停止链
public class MyInterceptor extends AbstractPhaseInterceptor<Message> {
public MyInterceptor() {
super(Phase.POST_STREAM);
}
@Override
public void handleMessage(Message message) throws Fault {
if (message != null) {
//check the condition to raise the error
//build the custom Response replacing service call
Response response = Response
.status(Response.Status.BAD_REQUEST)
.entity("custom error")
.build();
message.getExchange().put(Response.class, response);
//abort interceptor chain in you want to stop processing or throw a Fault (catched by handleFault)
//message.getInterceptorChain().abort();
//throw new Fault (new MyException());
}
public void handleFault(Message messageParam) {
}
}
在创建 JAXRS 客户端时添加 ResponseExceptionMapper 作为提供者
providers.add(new ResponseExceptionMapper<WebApplicationException>() {
@Override
public WebApplicationException fromResponse(Response r) {
return new WebApplicationException(r);
}
});
YourService proxy = JAXRSClientFactory.create(url, clazz,providers);
Client client = WebClient.client(proxy);
WebClient.getConfig(client).getInInterceptors().add(new MyInterceptor());
在此之后,如果完成拦截器检查,对 proxy.yourService()
的调用将引发 WebApplicationException
。您可以按需要的方式捕捉或重新抛出
try{
proxy.yourService();
}catch (WebApplicationException e){
}
希望对您有所帮助
我完全同意之前的回答。我的实现看起来像:
@Component
public class ServiceFailureInterceptor extends AbstractPhaseInterceptor<Message> {
private static final Logger LOG = LoggerFactory.getLogger(ServiceFailureInterceptor.class);
public ServiceFailureInterceptor() {
super(PRE_STREAM);
}
@Override
public void handleMessage(Message message) {
if (message != null) {
int responseCode = (int) message.get(Message.RESPONSE_CODE);
LogicException logicException = ErrorMapper.HTTP_STATUS_CODE_MAPPER.get(responseCode);
InputStream is = b2stream(MapperUtils.json().toBytes(logicException));
// clear old message & exchange
Exchange exchange = message.getExchange();
for (Class<?> contentFormat : message.getContentFormats()) {
message.setContent(contentFormat, null);
}
resetOrigInterceptorChain(message);
resetFault(exchange);
message.setContent(InputStream.class, is);
Message outMessage = createOutMessage(exchange, is);
prepareMessage(outMessage);
prepareMessage(message);
}
}
private void prepareMessage(Message message) {
message.put(Message.REQUESTOR_ROLE, true);
message.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
}
private Message createOutMessage(Exchange exchange, InputStream logicException) {
Endpoint ep = exchange.get(Endpoint.class);
Message outMessage = ep != null ? ep.getBinding().createMessage() : new MessageImpl();
outMessage.setContent(InputStream.class, logicException);
exchange.setOutMessage(outMessage);
outMessage.setExchange(exchange);
return outMessage;
}
private void resetFault(Exchange exchange) {
exchange.put(Exception.class, null);
}
private void resetOrigInterceptorChain(Message message) {
InterceptorChain chain = message.getInterceptorChain();
if (chain != null) {
for (Interceptor<?> interceptor : chain) {
chain.remove(interceptor);
}
chain.reset();
}
}
}
手动设置此异常后,我将转到 ExceptionMapper 实现,其中使用我的 LogicException 并构建异常响应。当通过 WebClient 声明为提供程序时,我无法避免异常映射器,因此我决定使用它并稍后重新映射异常。