簡體   English   中英

Apache 駱駝 REST 端點未返回最終主體

[英]Apache Camel REST endpoint not returning the final body

我已經聲明了一個 REST 端點,它使用direct調用另一個路由。 在第二條路線的最后,我正在記錄正文,但它與返回瀏覽器的正文不同。

這是一個重現該行為的小示例(我使用 Apache Camel 和 Spring 引導):

@Component
public class EntidadeRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        restConfiguration().bindingMode(json);

        rest("/entidade")
            .get("/{id}")
                .to("direct:search-by-id");

        from("direct:search-by-id")
            .routeId("search-by-id")
            .setProperty("idEntidade", simple("${header.id}"))
            .pollEnrich("file:files/mock/dados?noop=true&idempotent=false")
            .unmarshal().json(JsonLibrary.Jackson)
            .split(jsonpath("$"))
            .filter(jsonpath("$[?(@.id == ${property.idEntidade})]"))
            .marshal().json(JsonLibrary.Jackson)
            .log("${body}");
    }
}

我從瀏覽器調用它,使用 URL: http://localhost:8080/camel/entidade/1。

在文件夾files/mock/dados我有一個名為entidades.json的文件,其中有一個 JSON 數組(見下文)。

我知道拆分和過濾器正在工作,因為我在最后一行代碼中記錄了正文,這就是日志中顯示的內容:

2021-04-28 18:15:15.707 INFO 3905542 --- [nio-8080-exec-1] search-by-id: {"id":"1","tipo":"PF","nome" :"若昂瑪麗亞"}

但這是返回給瀏覽器的內容( entidades.json文件的確切內容):

[{"id":"1","tipo":"PF","nome":"João Maria"},{"id":"2","tipo":"PF","nome":" Maria João"},{"id":"3","tipo":"PF","nome":"João Silva"},{"id":"4","tipo":"PF","名稱":"何塞·索薩"}]

為什么記錄的正文與瀏覽器中顯示的不同並修復它?

PS:如果我刪除那些 marshal 和 unmarshal 調用,我會在瀏覽器中收到以下錯誤:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.apache.camel.component.file.FileBinding and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.apache.camel.component.file.GenericFile["binding"])

如果沒有輸入文件並知道您調用的具體 URI(包括路徑變量{id}的給定值),我只能懷疑以下一些問題:

  • 您是否在 GET 調用結束時提供了ID
  • 為什么要轉換 JSON?
  • 您是否測試了正確的拆分? 你又聚合了嗎?
  • 您想記錄每條消息嗎?

REST 端點

您將端點指定為GET /entidada/{id} {id}是一個路徑變量。

因此,假設您使用 1 作為 ID 調用GET /entidata/1 然后輪詢(讀取)您的 JSON 文件,解組到...?

JSON 解組/編組

這些unmarshal marshal 和marshal方法要么用於在不同的數據格式之間進行轉換,要么用於從數據表示轉換為 Java 對象 (POJO),如果它們在內部使用(例如傳遞給處理器 Bean 等)。

我想文件dados包含文本數據為 JSON。 因此,您可以簡單地將此文本讀入(文本)消息正文(如文本消息。比較 JMS 等:)並使用它,(a)按 JSON 路徑拆分,(b)按 JSON 路徑過濾, (c) 記錄這個 JSON 結果。 (d) 將其作為 HTTP 響應發送回調用客戶端(例如您的瀏覽器)。

分裂會發生什么?

在此之后,您嘗試拆分(假設您有一個 JSON 數組):

//  incoming:
//  a single enriched message, in body: JSON-array with 4 elements 
.split(jsonpath("$")) // what do you expect as output ?
// here the split usually should be ended using `.end` DSL method
.filter(jsonpath("$[?(@.id == ${property.idEntidade})]")) // each array element of JSON body matched against id, e.g. 1

我將您的 HTTP 響應(包含 4 個人的 JSON 數組)填充到在線JSON-path evaluator中。 $的評估不是拆分,而是單個元素(在結果數組內):正是原始數組(有 4 人)。


  • 為什么文件沒有分成 4 條消息,每條消息都包含一個人對象?
  • 因為您的 JSON-path $僅表示root-element

加:通常在.split()之后有一個.end()再次聚合它們。

你把它漏掉了。 我想這也是一個問題。


過濾器按預期工作

后來你過濾了 REST 給定的id

.filter(jsonpath("$[?(@.id == ${property.idEntidade})]"))`

這導致記錄的元素:

{"id":"1","tipo":"PF","nome":"João Maria"}

過濾器成功運行:只留下一個 id 為1的過濾器。

登錄駱駝

日志 EIP

.log()添加到路由鏈時,這意味着您正在使用Log EIP 在其文檔中給出了警告提示

使用流式消息記錄消息正文:

如果消息體是基於 stream 的,那么記錄消息體,之后可能會導致消息體為空。 請參閱此常見問題解答 對於流式消息,您可以使用 Stream 緩存來允許記錄消息正文並在之后再次讀取消息正文。

因此,當使用它來記錄基於流的消息體時,您的空日志消息可能是由副作用引起的。

日志方法的區別

在 DSL 和 Log 組件中的日志差異部分中進行了解釋:

日志 DSL 更輕量級,用於記錄人類日志,例如Starting to do …等。

下面的示例(根據您的 REST 路線調整)說明了它的用法:

rest("/entidade")
    .get("/{id}")
    .log("Processing ${id}")
    .to("bean:foo");

日志組件

我建議使用標准Log組件,只需使用.to() DSL 傳遞基於模式log:的 URI 字符串以及所需的參數loggerName

.to("log:filtered-json")

這里Log組件的 URI 前綴是log: stream 的每條消息都使用loggerName filtered-json進行記錄。

錯誤是我需要將AggregationStrategy傳遞給split 我還需要停止記錄正文,因為它正在消耗 InputStream。 在那之后,我可以安全地刪除那些 marshal 和 unmarshal 調用。

這是最終代碼:

@Component
public class EntidadeRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        restConfiguration().bindingMode(json);

        rest("/entidade")
            .get("/{id}")
                .to("direct:search-by-id");

        from("direct:search-by-id")
            .routeId("search-by-id")
            .setProperty("idEntidade", simple("${header.id}"))
            .pollEnrich("file:files/mock/dados?noop=true&idempotent=false")
            .split(jsonpath("$"), takeFirst(Exchange.FILTER_MATCHED))
                .filter(jsonpath("$[?(@.id == ${property.idEntidade})]")).stop()
            .end();
    }

    private AggregationStrategy takeFirst(String matchProperty) {
        return ((oldExchange, newExchange) -> {
            if (oldExchange == null && newExchange.getProperty(matchProperty, Boolean.class)) {
                oldExchange = newExchange;
            }
            return oldExchange;
        });
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM