当前位置: 首页 > 知识库问答 >
问题:

将异常从CXF侦听器传播到异常映射器

容远
2023-03-14

我有一个流程,在CXF客户机上,我在拦截器、提供者和异常映射器中有JAXR。在我的例子中,我通过截取程序捕捉到来自客户端的错误响应,然后我想中止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过滤器,因为拦截器抛出的异常不会传播到异常映射器。借助WebClient实现,在java中有没有办法做到这一点?

S client = create(url, clazz, list(jsonProvider(), providers));
WebClient.getConfig(client).getInInterceptors().add(new MyInterceptor());

我也尝试过在拦截器上使用不同的阶段,但也不起作用。

共有2个答案

金子平
2023-03-14

我完全同意前面的回答。我的实现看起来像:

@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实现,在该实现中,我的逻辑异常被消耗,异常响应正在构建。当通过WebClient声明为提供者时,我无法避免异常映射器,所以我决定使用它并稍后重新映射异常。

晋鹤轩
2023-03-14

我一直在研究和测试你的问题。问题是,从CXF拦截器抛出的异常逃逸了JAX-RS流(请参阅CXF团队的答案)

从拦截器生成的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;
    }
}

但您不能从拦截器返回自定义响应,也不能向客户端响应错误。

我发现的实现所需行为的变通方法包括用一个自定义对象替换响应,该对象可以通过您通常的方法调用来处理,比如异常映射器。请参阅CXF/JAX-RS:从拦截器返回自定义响应

进入拦截器。handleMessage检查所需的条件,并创建一个带有自定义状态和实体的响应。之后,停止链条

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){
}

希望这有帮助

 类似资料:
  • 问题内容: 我有一个流程,在CXF客户端上我安装了拦截器,提供程序和异常映射程序。就我而言,我正在通过拦截器捕获来自客户端的不良响应,然后我想中止cxf总线链并引发故障。不幸的是我做不到,因为在每种情况下都只记录从拦截器抛出的异常,但是主要错误(错误的json格式)会传播到异常映射器。我想避免使用异常映射器,但是我不知道怎么做。我正在使用WebClient来实现这样的拦截器: 我读到我应该实现ja

  • 我试图让队列在laravel 5中工作,队列侦听器正在输出: 未定义索引:表 存在"作业"和"failed_jobs"表,config.php设置为"数据库"。 搜索laravel论坛和google都没有找到解决办法,艾米的想法去哪里找?

  • 我有一个.NET应用程序,其中有一个用于接收用户请求的控制器,一个服务调用另一个服务。我在中有一些代码,当用户请求值不正确时,我查询数据库(DynamoDB)并得到500错误的响应。我想处理这个问题,这样我就可以捕捉到这个错误/异常,并将错误消息连同一个400状态码一起从控制器发回给用户。我应该如何修改代码来做到这一点? 这是我尝试过的。目前,我只是在中打印错误,但我需要将其发送到控制器。通过抛出

  • 我正在努力使用Java Spring Hibernate,我正在尝试实现Oauth2,在通过@ManyToMany将表用户连接到角色时,我不断遇到错误。我已经阅读了所有关于我的问题的答案,无论我尝试什么,我仍然得到了一个组织。冬眠映射异常。 以下是我正在努力做的事情的全部细节。 数据库结构 角色。JAVA 使用者JAVA 依赖性 问题: org.springframework.beans.fact

  • 一个监听器里面的应用代码在运行期间可能会抛出异常。一些监听器通知发生在应用中的另一个组件调用树过程中。这方面的一个例子是一个Servlet 设置了会话属性,该会话监听器抛出未处理异常。容器必须允许未处理的异常由描述在10.9节“错误处理”的错误页面机制处理。如果没有为这些异常指定错误页面,容器必须确保返回一个状态码为500的响应。这种情况下,不再有监听器根据事件被调用。 有些异常不会发生在应用中的

  • 问题内容: 我正在使用Java 8的可完成的Future,并且希望能够处理将来抛出的异常并将其转换为其他异常。 一旦发生异常,我尝试过的所有复合材料似乎都会短路。 例如,使用scala future,我可以执行以下操作: 并且我希望能够在将来的Java复合块中模仿它。这可能吗? 问题答案: 您可以使用。例如 如果完成并带有异常,则将完成并带有潜在转换的异常。否则,它将具有相同的成功结果值。 关于我