我目前正在使用新的Camel REST DSL作为基础,开发基于REST的Java应用程序。 它主要起作用,除了我注意到通过REST客户端(而不是说浏览器)调用URL时,JSON响应是"乱码"并通过我认为是错误的编码
MyRouteBuilder.java
@Component
public class MyRouteBuilder extends RouteBuilder{
@Autowired
LocalEnvironmentBean environmentBean;
@Override
public void configure() throws Exception {
restConfiguration().component("jetty").host("0.0.0.0").port(80)
.bindingMode(RestBindingMode.auto);
rest("/testApp")
.get("/data").route()
.to("bean:daoService?method=getData")
.setProperty("viewClass", constant(CustomeJsonViews.class))
.marshal("customDataFormat").endRest()
.get("/allData").route()
.to("bean:daoService?method=getDatas")
.setProperty("viewClass", constant(CustomeJsonViews.class))
.marshal("customDataFormat").endRest();
}
}
CustomeDataFormat.java
public class CustomDataFormat implements DataFormat{
private ObjectMapper jacksonMapper;
public CustomDataFormat(){
jacksonMapper = new ObjectMapper();
}
@Override
public void marshal(Exchange exchange, Object obj, OutputStream stream) throws Exception {
Class view = (Class) exchange.getProperty("viewClass");
if (view != null)
{
ObjectWriter w = jacksonMapper.writerWithView(view);
w.writeValue(stream, obj);
}
else
stream.write(jacksonMapper.writeValueAsBytes(obj));
}
@Override
public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
return null;
}
}
可在此处找到完整的工作版本: https://github.com/zwhitten/camel-rest-test
例如,在Chrome中访问网址{host} / testApp / data时,响应如下:
{
data: "Sherlock",
value: "Holmes",
count: 10
}
然而,使用Postman浏览器插件作为客户端返回:
"W3siZGF0YSI6ImRhdGE6OjAiLCJ2YWx1ZSI6InZhbHVlOjowIiwiY291bnQiOjB9LHsiZGF0YSI6ImRhdGE6OjEiLCJ2YWx1ZSI6InZhbHVlOjoxIiwiY291bnQiOjF9LHsiZGF0YSI6ImRhdGE6OjIiLCJ2YWx1ZSI6InZhbHVlOjoyIiwiY291bnQiOjJ9LHsiZGF0YSI6ImRhdGE6OjMiLCJ2YWx1ZSI6InZhbHVlOjozIiwiY291bnQiOjN9LHsiZGF0YSI6ImRhdGE6OjQiLCJ2YWx1ZSI6InZhbHVlOjo0IiwiY291bnQiOjR9LHsiZGF0YSI6ImRhdGE6OjUiLCJ2YWx1ZSI6InZhbHVlOjo1IiwiY291bnQiOjV9LHsiZGF0YSI6ImRhdGE6OjYiLCJ2YWx1ZSI6InZhbHVlOjo2IiwiY291bnQiOjZ9LHsiZGF0YSI6ImRhdGE6OjciLCJ2YWx1ZSI6InZhbHVlOjo3IiwiY291bnQiOjd9LHsiZGF0YSI6ImRhdGE6OjgiLCJ2YWx1ZSI6InZhbHVlOjo4IiwiY291bnQiOjh9LHsiZGF0YSI6ImRhdGE6OjkiLCJ2YWx1ZSI6InZhbHVlOjo5IiwiY291bnQiOjl9XQ=="
问题似乎是REST绑定模式是" auto"并使用自定义marshaller。 如果我将绑定模式设置为" json"然后浏览器和客户端响应都会出现乱码。 如果我将绑定模式设置为" json"并绕过定制marshallers一切正常。 有没有办法配置路由使用自定义编组器并正确编码响应,无论客户端?
答案 0 :(得分:8)
我认为解决方案是使用默认绑定选项(关闭),因为您使用的是自定义封送器。
答案 1 :(得分:3)
您有两种方法可以实现它:
注册您自己的DataFormat并自动在RestBinding中使用它。您可以通过jsonDataFormat
配置REST配置以设置自定义数据格式。
Map<String, DataFormatDefinition> dataFormats = getContext().getDataFormats();
if (dataFormats == null) {
dataFormats = new HashMap<>();
}
dataFormats.put("yourFormat", new DataFormatDefinition(new CustomDataFormat()));
restConfiguration()....jsonDataFormat("yourFormat")
答案 2 :(得分:0)
您也可以像这样创建自己的数据格式:
在你的restconfiguration中它会看起来像这样(参见json-custom)
builder.restConfiguration().component("jetty")
.host(host(propertiesResolver))
.port(port(propertiesResolver))
.bindingMode(RestBindingMode.json)
.jsonDataFormat("json-custom")
;
您必须创建一个文件“json-custom”
所以文件的内容应该是:
class=packageofmyclass.MyOwnDataformatter
答案 3 :(得分:0)
您收到的回复是JSON,但已编码为base64。从你的帖子中取出字符串,我能够将其解码为:
[{ “数据”: “数据:: 0”, “值”: “值:: 0”, “计数”:0},{ “数据”: “数据:: 1”, “值”: “值:: 1”, “计数”:1},{ “数据”: “数据:: 2”, “值”: “值:: 2”, “计数”:2},{ “数据”:”数据:: 3" , “值”: “值:: 3”, “计数”:3},{ “数据”: “数据:: 4”, “值”: “值:: 4”, “计数” :4},{ “数据”: “数据:: 5”, “值”: “值:: 5”, “计数”:5},{ “数据”: “数据:: 6”, “值”: “值:: 6”, “计数”:6},{ “数据”: “数据:: 7”, “值”: “值:: 7”, “计数”:7},{ “数据”:”数据:: 8" , “值”: “值:: 8”, “计数”:8},{ “数据”: “数据:: 9”, “值”: “值:: 9”, “计数” :9}]
上面的答案阻止响应体被编码为base64。 Apache Camel在 bindingMode 上提供的文档很难说明为什么它与显式编组相结合时的行为方式。删除显式编组将返回JSON正文,但您可能还注意到它包含正文中的任何类名。文档建议bindingMode更多用于类的传输,并且您指定了请求/响应的类型(Pojo.class)和可选的outType(Pojo.class)。有关更多详细信息,请参阅http://camel.apache.org/rest-dsl.html(绑定到POJO使用部分)。
根据我读过的一些帖子,Base64是跨网络传输JSON的最安全的方式,以确保它与服务器发送的完全一样。然后客户负责解码响应。
上述答案可以解决问题。但是,我并不完全相信在服务路由中混合数据格式是好事,理想情况下应该处于更高的抽象层次。这样就可以在一个地方更改数据格式,而不必在生成JSON的每个路径上更改它。虽然,我必须承认,我从来没有见过一种在其生命周期中改变数据格式的服务,所以这真的是一个静音点。
答案 4 :(得分:0)
我们也面临着同样的问题。 我们的数据格式是Json。一旦我们实施了自定义编组器。骆驼将数据编码为base64。我尝试了Cshculz提供的方法,但由于某种原因(我不知道原因)而未调用我们的CustomDataFormatter。
因此我们在每个Bean调用之后都添加了 .marshal(YourDataFormatter)。这为我们提供了格式化的json,但是以编码形式提供了,因此在路由的最后,我们添加了 .unmarshal( ).json(JsonLibrary.Jackson)返回原始json到客户端。
示例代码段:-
.to(“ xxxxxxx”)。marshal(YourDataFormatterBeanRef)
.to(“ xxxxxxx”)。marshal(YourDataFormatterBeanRef)
.to(“ xxxxxxx”)。marshal(YourDataFormatterBeanRef)
.to(“ xxxxxxx”)。marshal(YourDataFormatterBeanRef)
.end()。unmarshal()。json(JsonLibrary.Jackson)