项目组要和被收购的公司做接口对接,使用camel进行集成。在使用的过程当中,我们几个小伙伴都遇到了一个相同的问题:请求request body的内容失踪了。这里贴出有问题的路由配置:
<?xml version="1.0" encoding="UTF-8"?>
<routes xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="rest:post:sett/pay/apply.json"/>
<log message="接收clivet请求, ${body}"/>
<setProperty name="template_code">
<constant>clivet_payment_request_json</constant>
</setProperty>
<process ref="json2TemplateProcessor"/>
<to uri="netty-http:http://127.0.0.1:1234/****/save.json"/>
<!-- ?httpMethod=POST&transferExchange=true -->
</route>
</routes>
原因是from接口后紧随的log把HttpRequest的InputStream给消费掉了。导致转发的请求的springmvc读不到数据。把 ${body}去掉即可解决问题。
给出我的排查过程。
debug CamelServlet的入口方法
at org.apache.camel.http.common.HttpHelper.readRequestBodyFromServletRequest(HttpHelper.java:147)
at org.apache.camel.http.common.DefaultHttpBinding.parseBody(DefaultHttpBinding.java:646)
at org.apache.camel.http.common.HttpMessage.createBody(HttpMessage.java:101)
at org.apache.camel.support.MessageSupport.getBody(MessageSupport.java:65)
at org.apache.camel.http.common.DefaultHttpBinding.readBody(DefaultHttpBinding.java:193)
at org.apache.camel.http.common.DefaultHttpBinding.readRequest(DefaultHttpBinding.java:118)
at org.apache.camel.http.common.HttpMessage.init(HttpMessage.java:73)
at org.apache.camel.http.common.HttpMessage.<init>(HttpMessage.java:39)
at org.apache.camel.http.common.CamelServlet.doExecute(CamelServlet.java:274)
at org.apache.camel.http.common.CamelServlet.doService(CamelServlet.java:214)
at org.apache.camel.http.common.CamelServlet.service(CamelServlet.java:130)
2. 进入 org.apache.camel.processor.LogProcessor#process 方法这里camel会消费exchange的InputStreamCahce。
读完之后,这个流就close了,你是无法再次读出来了。至此,破案。
我们组三个小伙伴都遇到了这个问题,camel官方也意识到了这个问题。官方faq :WHY IS MY MESSAGE EMPTY?
In Camel the message body can be of any types. Some types are safely readable multiple times, and therefore do not ‘suffer’ from becoming ‘empty’. So when you message body suddenly is empty, then that is often related to using a message type that is no re-readable; in other words, the message body can only be read once. On subsequent reads the body is now empty. This happens with types that are streaming based, such as java.util.InputStream, etc.
意即inputstream不能重复消费。
camel给出的解决方案 STREAM CACHING,把inputstream缓存起来,供后续重复读。
需要增加如下配置
context.getStreamCachingStrategy().setSpoolEnabled(true);
context.getStreamCachingStrategy().setSpoolDirectory("/tmp/cachedir");
context.getStreamCachingStrategy().setSpoolThreshold(64 * 1024);
context.getStreamCachingStrategy().setBufferSize(16 * 1024);
context.setStreamCaching(true);
${body}可以在某个processor消费了inputstream后再使用,但决不能紧跟着from节点用。