Apache Camel:如何在不提前marshal的情况下条件设置Header、Body并使用toD()
Apache Camel:保留原Body同时实现动态HTTP路由配置
你的问题核心是修改Body后丢失了原MyCompositePojo实例,导致后续toD()无法访问configDetail.url。Camel的choice()完全支持条件设置Header,但修改Body会替换Exchange中的当前Body对象,这是问题的根源,和choice()本身无关。
下面是几种可行的解决方案,按实现复杂度从低到高排序:
方案1:暂存原Body到Exchange属性(最简洁)
在修改Body之前,把原MyCompositePojo存入Exchange的**属性(Property)**中(属性不需要序列化,适合路由内临时存储),后续需要访问原对象时直接从属性中获取:
from("direct:eventHttpChoice") .log(....) .setProperty("originalComposite", body()) // 把原Body存入Exchange属性 .setHeader("Authorization", simple("Bearer ${body.token}")) .setHeader(Exchange.HTTP_METHOD, simple("${body.httpMethod.name}")) .choice() .when(simple("${body.httpMethod.name} in 'PUT,DELETE'")) .setHeader(Exchange.HTTP_PATH, simple("${body.newEvent.number}")) .endChoice() .end() .choice() .when(simple("${body.httpMethod.name} in 'POST,PUT'")) .setHeader(HttpHeaders.CONTENT_TYPE, constant(MediaType.APPLICATION_JSON)) .setBody(simple("${body.newEvent}")).marshal().json(JsonLibrary.Jsonb) .endChoice() .otherwise() // DELETE .when(simple("${body.configDetail.http.deleteSomeField} == 'true' && ${body.newEvent.someField} != null && ${body.newEvent.someField} != ''")) .setHeader(Exchange.HTTP_QUERY, simple("someField=${body.newEvent.someField}&operationId=${body.newEvent.operationId}")) .endChoice() .otherwise() .setHeader(Exchange.HTTP_QUERY, simple("operationId=${body.newEvent.operationId}")) .endChoice() .endChoice() .end() .log(LoggingLevel.INFO, "Sending to this url: ${exchangeProperty.originalComposite.configDetail.url}") .toD("${exchangeProperty.originalComposite.configDetail.url}", 10); // 从属性中获取原对象的URL
方案2:使用自定义Header暂存原Body
和方案1逻辑一致,只是把原对象存入Header而非Property。注意如果路由跨序列化场景(比如跨JVM、消息队列),Header需要支持序列化:
from("direct:eventHttpChoice") .log(....) .setHeader("originalComposite", body()) // 把原Body存入Header // ... 中间逻辑不变 .log(LoggingLevel.INFO, "Sending to this url: ${header.originalComposite.configDetail.url}") .toD("${header.originalComposite.configDetail.url}", 10);
方案3:用Bean封装HTTP配置逻辑(面向对象)
将HTTP头、请求体的配置逻辑封装到一个Java Bean中,全程不修改原Body,而是把需要的请求体存入Header,后续toD()通过Header指定请求体:
第一步:编写配置Bean
import jakarta.json.bind.Jsonb; import jakarta.json.bind.JsonbBuilder; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.springframework.http.MediaType; import java.nio.charset.StandardCharsets; public class HttpRequestConfigurer { public void configure(Exchange exchange) { Message in = exchange.getIn(); MyCompositePojo composite = in.getBody(MyCompositePojo.class); // 配置HTTP_PATH(PUT/DELETE场景) String method = composite.getHttpMethod().name(); if ("PUT".equals(method) || "DELETE".equals(method)) { in.setHeader(Exchange.HTTP_PATH, composite.getNewEvent().getNumber()); } // 配置请求体(POST/PUT场景) if ("POST".equals(method) || "PUT".equals(method)) { in.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); Jsonb jsonb = JsonbBuilder.create(); String payloadJson = jsonb.toJson(composite.getNewEvent()); in.setHeader("requestPayload", payloadJson.getBytes(StandardCharsets.UTF_8)); } // 配置查询参数(DELETE场景) if ("DELETE".equals(method)) { boolean deleteSomeField = "true".equals(composite.getConfigDetail().getHttp().getDeleteSomeField()); String someField = composite.getNewEvent().getSomeField(); String operationId = composite.getNewEvent().getOperationId(); if (deleteSomeField && someField != null && !someField.isEmpty()) { in.setHeader(Exchange.HTTP_QUERY, String.format("someField=%s&operationId=%s", someField, operationId)); } else { in.setHeader(Exchange.HTTP_QUERY, String.format("operationId=%s", operationId)); } } } }
第二步:在路由中调用Bean
from("direct:eventHttpChoice") .log(....) .setHeader("Authorization", simple("Bearer ${body.token}")) .setHeader(Exchange.HTTP_METHOD, simple("${body.httpMethod.name}")) .bean(HttpRequestConfigurer.class) // 调用Bean完成配置,原Body不变 .log(LoggingLevel.INFO, "Sending to this url: ${body.configDetail.url}") // 通过body参数指定从Header取请求体 .toD("${body.configDetail.url}?body=${header.requestPayload}", 10);
关键注意点
- Exchange的Body是单一值,修改后会覆盖原对象,这是Camel的核心设计,和
choice()无关; - Exchange属性(
exchangeProperty)是路由内的临时存储,不会被序列化,适合存储复杂对象; - 如果需要跨组件传递原对象,确保对象实现
Serializable,再存入Header。
内容的提问来源于stack exchange,提问作者WesternGun
相关产品推荐
相关产品推荐

