我对骆驼比较陌生。在实现以下功能时,我遇到了这个问题。
要求:调用GET服务,如果响应的状态不是200以外的任何其他状态,则需要抛出HttpOperationFailedException,以便204异常可以在父路由上使用onException进行处理。
我可以使用以下代码实现它:
from("direct:parent")
.onException(HttpOperationFailedException.class)
.onWhen(exchange ->{
HttpOperationFailedException exe = exchange.getException(HttpOperationFailedException.class);
if(204 == exe.getStatusCode()){
return true;
}
return false;
})
.setBody(constant(null))
.end()
.to("direct:a");
from("direct:a")
.recipientList("false")
.simple("http4://localhost:8022/test/service?okStatusCodeRange=200-201")
.convertBodyTo(String.class);
但是,使用以下代码时不会引发异常:
from("direct:parent")
.onException(HttpOperationFailedException.class)
.onWhen(exchange ->{
HttpOperationFailedException exe = exchange.getException(HttpOperationFailedException.class);
if(204 == exe.getStatusCode()){
return true;
}
return false;
})
.setBody(constant(null))
.end()
.to("direct:a");
from("direct:a")
.to("http4://localhost:8022/test/service?okStatusCodeRange=200-201")
.convertBodyTo(String.class);
任何人都可以解释需要进行哪些更改才能使用它,而不是收件人列表吗?
当你从传播的HTTP URI调用direct:parent
到direct:a
,但保持在一个嵌套的例外条款direct:parent
,在抛出的异常direct:a
是不向上传播到父路径。但是,您应该做的是将嵌套异常子句重构为全局异常子句。
我创建了一个简单的测试用例,它可以模拟在204消息上引发的异常,或者可以调用真实服务并在204响应的情况下失败:
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.AdviceWithRouteBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.http.common.HttpOperationFailedException;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
public class Http4ExceptionHandlingTest extends CamelTestSupport {
@Produce(uri = "direct:parent")
protected ProducerTemplate template;
@Override
public boolean isUseAdviceWith() {
return true;
}
@Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
onException(HttpOperationFailedException.class)
.onWhen(exchange -> {
HttpOperationFailedException
exe = exchange.getException(HttpOperationFailedException.class);
return 204 == exe.getStatusCode();
})
.log("HTTP exception handled")
.handled(true)
//.continued(true)
.setBody(constant(null));
from("direct:parent").routeId("parent")
// .onException(HttpOperationFailedException.class)
// .onWhen(exchange -> {
// HttpOperationFailedException
// exe = exchange.getException(HttpOperationFailedException.class);
// return 204 == exe.getStatusCode();
// })
// .setBody(constant(null))
// .end()
.log("Parent start");
.to("direct:a")
.log("Parent done");
from("direct:a").routeId("a")
.log("a start")
.to("http4://localhost:8022/test/service?okStatusCodeRange=200-201")
.convertBodyTo(String.class)
.log("a done");
}
};
}
@Test
public void testExceptionHandling() throws Exception {
// comment the following line out if you want to invoke the real service instead!
weaveRoute();
context.start();
Object response = template.requestBody("foo");
assertThat(response, is(nullValue()));
}
@Test
public void testSuccessfulResponse() throws Exception {
// comment the following line out if you want to invoke the real service instead!
weaveRoute();
context.start();
Object response = template.requestBody("bar");
assertThat(response, is(equalTo("bar")));
}
private void weaveRoute() throws Exception {
context.getRouteDefinition("a").adviceWith(context, new AdviceWithRouteBuilder() {
@Override
public void configure() throws Exception {
this.interceptSendToEndpoint("http4*")
.skipSendToOriginalEndpoint()
.process(exchange -> {
String body = exchange.getIn().getBody(String.class);
if ("foo".equals(body)) {
Map<String, String> headers = new HashMap<>();
String location = "";
HttpOperationFailedException exe =
new HttpOperationFailedException("http://bla", 204, "No Content", location,
headers, "response body");
throw exe;
}
});
}
});
}
}
我在父路由中保留了原始的嵌套异常子句,以便您可以比较结果。全局异常处理程序还有一条额外的.handled(true
)`语句,它刚刚超出了当前路由。因此,文档指出以下内容:
如果handle为true,则将处理抛出的异常,并且Camel将不会继续沿原始路由进行路由,而是会中断。但是,您可以在onException中配置一个路由,该路由将被代替使用。如果您需要创建一些返回给调用者的自定义响应消息,或者执行其他任何处理(因为引发了该异常),则可以使用此路由。(来源)
不将捕获的异常设置为.handled(true)
会导致堆栈跟踪的呈现,然后继续执行。
我添加了更多的日志语句以可视化异常处理中的行为。执行上面提供的代码后,您将获得类似以下的输出:
[INFO ] - - Parent start [ ] [parent] [ ] [main]
[INFO ] - - a start [ ] [a] [ ] [main]
[INFO ] - - HTTP exception handled [ ] [a] [ ] [main]
取而代之的是,.handled(true)
您也可以使用.continued(true)
以便按照记录进行执行:
如果continue为true,那么Camel将捕获该异常,并且实际上只是忽略该异常并继续沿原始路由进行路由。但是,如果在onException中配置了路由,它将先路由该路由,然后再继续在原始路由中路由。
在全局异常子句中启用.continued(true)
和禁用测试的情况下运行测试.handled(true)
将产生以下日志:
[INFO ] - - Parent start [ ] [parent] [ ] [main]
[INFO ] - - a start [ ] [a] [ ] [main]
[INFO ] - - HTTP exception handled [ ] [a] [ ] [main]
[ERROR] - - Failed delivery for (MessageId: ...). Exhausted after delivery attempt: 1 caught: null. Handled and continue routing.
Message History
---------------------------------------------------------------------------------------------------------------------------------------
RouteId ProcessorId Processor Elapsed (ms)
[parent ] [parent ] [direct://parent ] [ 8]
[parent ] [log9 ] [log ] [ 0]
[parent ] [to4 ] [direct:a ] [ 8]
[a ] [log7 ] [log ] [ 1]
[a ] [to3 ] [http4://localhost:8022/test/service?okStatusCodeRange=200-201 ] [ 8]
[ ] [process2 ] [Processor@0x3c7f66c4 ] [ 8]
[a ] [log6 ] [log ] [ 1]
[a ] [setBody2 ] [setBody[{null}] ] [ 0]
Stacktrace
--------------------------------------------------------------------------------------------------------------------------------------- [ ] [o.a.c.p.DefaultErrorHandler] [ ] [main]
org.apache.camel.http.common.HttpOperationFailedException: HTTP operation failed invoking http://bla with statusCode: 204, redirectLocation:
at at.erpel.messaginghub.services.unit.routes.rest.Http4ExceptionHandlingTest$2.lambda$configure$1(Http4ExceptionHandlingTest.java:103)
at org.apache.camel.processor.DelegateSyncProcessor.process(DelegateSyncProcessor.java:63)
...
[INFO ] - - a done [ ] [a] [ ] [main]
[INFO ] - - Parent done [ ] [parent] [ ] [main]
从简化的日志中可以看出,.continued(true)
尽管会记录一条消息历史记录以及被忽略异常的堆栈跟踪信息,但不会超出路由范围。
如果父路由中有嵌套异常子句,而子路由确实遇到异常,则在嵌套异常子句中添加.handled(true)
或.continuted(true)
无效,因为子路由中捕获的实际异常不会传播到父嵌套异常子句,并且因此根本没有处理。
我已经针对模拟和真实服务测试了代码示例,该真实服务返回了204
接收到foo
正文的200
响应以及接收到其他内容的响应。?okStatusCodeRange=200-201
因此,在我的情况下,配置参数可以按预期工作。对于完整性:我正在使用Camel 2.17.0。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句