7

我想在路由结束时处理请求和响应消息。但是,我看不到如何访问原始请求消息的方法。

我有一种可怕的感觉,我正在为一些基本概念而苦苦挣扎。

这是 DSL 中的一个简单示例路由,用于概述我的问题(为整个上下文启用了流缓存):

from("activemq:queue:myQueue")
.to("log:" + getClass().getName() + "?showOut=true")
.to("http://localhost:8080/someBackend")
.log("Now in.Body returns this: ${in.body} and out.Body this: ${out.body}")
.to("log:" + getClass().getName() + "?showOut=true");

这是我的日志的相应摘录(为了更好地阅读而编辑了换行符)。可以看到,一旦 http 服务器回复,原始的 SOAP 消息就丢失了,SOAP 响应对象存储在消息的 inBody 中。

2012-09-25 17:28:08,312 local.bar.foo.MyRouteBuilder INFO - 
    Exchange[ExchangePattern:InOut, BodyType:byte[],
    Body:<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Header /><env:Body><urn:someRequest  xmlns:urn="http://foo.bar.local/ns"></urn:someRequest></env:Body></env:Envelope>, 
    Out: null]
2012-09-25 17:28:08,398 org.apache.camel.component.http.HttpProducer DEBUG - 
    Executing http POST method: http://localhost:8080/someBackend
2012-09-25 17:28:09,389 org.apache.camel.component.http.HttpProducer DEBUG - 
    Http responseCode: 200
2012-09-25 17:28:09,392 route2 INFO - 
    Now in.Body returns this: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:someResponse xmlns:ns2="http://foo.bar.local/ns"</ns2:someResponse></soap:Body></soap:Envelope>
    and out.Body this: 
2012-09-25 17:28:09,392 local.bar.foo.MyRouteBuilder INFO - 
    Exchange[ExchangePattern:InOut,  
    BodyType:org.apache.camel.converter.stream.InputStreamCache,
    Body:[Body is instance of org.apache.camel.StreamCache],
    Out: null]

我本来希望在整个路线上保留 in.body 和 out.body ?

我正在考虑的替代解决方案:

  • 利用Correlation Identifier模式来关联请求和回复。但这也会保留消息正文吗?此外,我的请求/回复消息没有用于关联的唯一标识符。
  • 编写一个自定义 bean,它执行对 http 后端的调用,同时处理请求和回复对象(但这基本上是一个非 Camel 解决方案,重新发明轮子,因此不是首选)

已经失败的方法:

我尝试在路由结束时使用这样的处理器访问原始请求消息,但没有成功:

 process(new Processor() {
   @Override
   public void process(Exchange exchange) throws Exception {
      Message originalInMessage = exchange.getUnitOfWork().getOriginalInMessage();
         logger.debug(originalInMessage.getBody(String.class));
         logger.debug(exchange.getIn().getBody(String.class));
   }
 });

谢谢你的帮助

4

4 回答 4

14

只需将 in 消息的原始正文存储在标头或属性中并在最后检索它:

from("activemq:queue:myQueue")
.setProperty("origInBody", body())
.to("http://localhost:8080/someBackend")

在 http 调用之后,您可以访问属性 origInBody。

于 2012-09-26T06:04:08.550 回答
13

首先,这篇文章很好地展示了骆驼的进出方式:http: //camel.apache.org/using-getin-or-getout-methods-on-exchange.html

通常,并不总是使用 out 消息,而是在每个步骤中从 in 消息中复制。

在您的情况下,您希望原始消息一直保留到路由结束,您可以继续使用 Enrichment EIP。http://camel.apache.org/content-enricher.html

您的路线将是这样的:

public class MyAggregationStrategy implements AggregationStrategy {
  public Exchange aggregate(Exchange orig, Exchange httpExchange){
    // if you want to check something with the Http request, you better do that here 
    if( httpExchange is not correct in some way ) 
       throw new RuntimeException("Something went wrong");

    return orig;
  }
}

AggregationStrategy aggStrategy = new MyAggregationStrategy();

from("activemq:queue:myQueue")
  .enrich("http://localhost:8080/someBackend",aggStrategy)
  .//keep processing the original request here if you like, in the "in" message
于 2012-09-25T19:52:15.480 回答
5

骆驼最大的问题之一,就是容易误用。正确使用它的最好方法是从 EIP 的角度来思考:camel 的主要目标之一是在其 DSL 中实现 EIP

这是EIP的列表

现在想想。你想要最后的请求和响应,有什么用?记录,聚合,... ? 对于日志记录,correlationId 就足够了,所以我认为您需要它来创建响应,基于请求和代理响应。如果这就是你想要的,你可以做类似的事情

from("direct:receiveRequest")
   .enrich("direct:proxyResponse", new RequestAndResponseAggregationStrategy())

您将有机会合并您的请求(在 oldExchange 中)和您的响应(在 newExchange 中)。

尽管我对 Christian Schneider 给予了应有的尊重,但我确实认为将请求放在可以稍后重用的属性中的想法是一个糟糕的设计。通过这样做,您会在路线之间产生副作用。如果您的路线是另一个路线的子路线,您可能会删除他们的财产。如果你把它存储起来以后放回去,也许你应该做类似的事情

from("direct:receiveRequest")
    .enrich("direct:subRouteToIgnoreResponse", AggregationStrategies.useOriginal())

我自己做了太多次的一个非常糟糕的设计是:

from("direct:receiveRequest")
    .to("direct:subroute")

from("direct:subroute")
    .setProperty("originalBody", body())
    .to("direct:handling")
    .transform(property("originalBody")

这将导致“属性/标题地狱”,以及只是处理器的连续调用的路由。

如果你想不出 EIP 问题的解决方案,你应该只使用骆驼来访问他们的组件。例如,类似:

from("http://api.com/services")
   .to(new SomeNotTranslatableToEIPProcessor())
   .to("ftp://destination")

但是不要忘记这些组件有它们自己的目标:在相似行为之间创建一个通用抽象(例如,基于时间的轮询消费者)。如果您有非常特定的需求,尝试将骆驼组件弯曲到这种特定需求可能会导致大量代码不易维护。

不要让 Camel 成为你的金锤反模式

于 2018-07-19T12:16:11.913 回答
0

我经常使用聚合策略,它保留旧的交换并将丰富的结果放入标题中:

import org.apache.camel.Exchange;
import org.apache.camel.processor.aggregate.AggregationStrategy;

public class SetBodyToHeaderAggregationStrategy implements AggregationStrategy {

    private String headerName = "newBody";

    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        oldExchange.getIn().setHeader(headerName, newExchange.getIn().getBody());

        return oldExchange;
    }

    @SuppressWarnings("unused")
    public void setHeaderName(String headerName) {
        this.headerName = headerName;
    }

}

现在你可以像这样使用它:

<enrich strategyRef="setBodyToHeaderAggregationStrategy">
  <constant>dosomething</constant>
</enrich>

<log loggingLevel="INFO" message="Result body from enrich: ${header.newBody}. Original body: ${body}" loggerRef="log"/>
于 2019-05-13T13:54:45.787 回答