Camel REST应用浏览器二次请求返回304/500异常排查求助
你的问题核心在于Camel路由没有正确处理Facebook接口返回的304 Not Modified响应,导致后续的Jackson反序列化步骤抛出异常,最终返回500错误。
为什么会出现这个问题?
当浏览器第一次请求后,收到了Camel返回的ETag头,第二次请求时会自动携带If-None-Match头。你的路由中removeHeaders("CamelHttp*")并没有移除客户端发送的If-None-Match(因为它不是以CamelHttp开头的请求头),所以这个头会被直接转发给Facebook的API。
Facebook API识别到If-None-Match后,会返回304状态码且没有响应体。但你的路由后续依然执行了.unmarshal("model-jackson-dataformat")步骤——Jackson试图解析空的响应体,自然会抛出异常,最终导致Camel返回500错误。而Postman默认不会自动发送If-None-Match头,所以不会触发这个问题。
解决方案
这里提供两种可行的解决思路,你可以根据需求选择:
方案1:拦截并处理304响应
在路由中检查Facebook接口返回的状态码,如果是304,则直接将该状态码返回给客户端,跳过反序列化步骤。修改你的路由代码如下:
rest("/facebook") .get("/name") .description("Gets the name of the Facebook application") .route().id("get-app-name-route") .removeHeaders("CamelHttp*") .setHeader(HTTP_METHOD, constant(GET)) .to("{{facebook.api.base.url}}/{{facebook.appID}}?fields=name&access_token={{facebook.permanentToken}}") // 添加分支处理304响应 .choice() .when(header(Exchange.HTTP_RESPONSE_CODE).isEqualTo(304)) // 直接返回304状态码,不执行反序列化 .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(304)) .setBody(constant(null)) .otherwise() .unmarshal("model-jackson-dataformat") .endChoice() .end() .endRest();
方案2:禁止转发客户端的缓存请求头
如果你希望每次都从Facebook获取最新数据(忽略浏览器的缓存请求),可以直接移除客户端发送的If-None-Match和If-Modified-Since头,这样Facebook API每次都会返回200和完整响应体,Camel就能正常处理:
rest("/facebook") .get("/name") .description("Gets the name of the Facebook application") .route().id("get-app-name-route") .removeHeaders("CamelHttp*") // 移除浏览器发送的缓存相关请求头,不转发给Facebook .removeHeader("If-None-Match") .removeHeader("If-Modified-Since") .setHeader(HTTP_METHOD, constant(GET)) .to("{{facebook.api.base.url}}/{{facebook.appID}}?fields=name&access_token={{facebook.permanentToken}}") .unmarshal("model-jackson-dataformat") .end() .endRest();
额外优化建议
如果希望Camel自己处理缓存逻辑(比如管理ETag和304响应),可以考虑:
- 使用Camel的
cache组件,缓存Facebook返回的结果和ETag - 当客户端发送
If-None-Match时,先对比本地缓存的ETag,如果匹配直接返回304,不调用Facebook API
这样可以减少对Facebook API的请求次数,同时避免转发缓存头带来的问题。
内容的提问来源于stack exchange,提问作者Spock

