关于Hessian一些报错的解决方案总结

Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能。 相比WebService,Hessian更简单、快捷。采用的是二进制RPC协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。这也正是工作时引入Hessian的一个重要原因,简单易配置。但是同样也有缺点,高版本对于低版本的向下兼容处理的并不好、一直流传一句话,“对于hessian,能不用高版本就不用高版本”,这句话充分说明了大家对于Hessian一些错误的困扰,那么下面总结一下最近遇到的Hessian相关的问题。

[size=large][color=red]1、Nginx 使用反向代理时 Hessian 的 411 错误[/color][/size]

[color=blue]报错如下:[/color]
com.caucho.hessian.client.HessianConnectionException: 411:java.io.IOException: Server returned HTTP response code: 411 for URL:http://xxxx/xxx/xxxService

[color=blue]排查过程:[/color]
刚一开始发现报错时,以为是server端返回的报错,还跑去问server端是不是报错了。。。后来了解到server端添加了nginx代理,不再支持绑定ip直连接口的方式。通过查资料发现Hessian在Nginx反向代理的情况下存在问题。

[color=blue]问题原因:[/color]
首先来看下 HTTP 411 错误的解释: Length Required 服务器不能处理请求,除非客户发送一个Content-Length 头。( HTTP 1.1 新)这是因为 Hessian 与服务端通信默认是采取分块的方式 (chunked encoding) 发送数据,而反向代理要获得 Content-Length 这个头,才能处理请求,但是 Hessian 的请求中并没有加入这个参数。

[color=blue]解决办法:[/color]
根据以上问题出现的原因,最直接想到的办法就是,缺少一个Content-Length那么我可以传递这个参数给server端,从而避免这个报错。具体办法是需要将将要发送的数据缓存下来。计算出content-length随着请求发送给server端,以满足Nginx需要这个参数的需求。
然而这样计算比较麻烦,所以可以使用Hessian提供的一个参数进行设置,setChunkedPost(false),(可以在初始化HessianFactory对象时写在构造函数里)这个是用来设置 Hessian 是否以分块发送的方式与服务端交换数据的参数,默认为true,设置为false时,向server端发送数据时就不采用分块方式,从而避免了报错。


[color=red][size=large]2、Hessian调用重载方法报错问题(expected end of call)[/size][/color]

[color=blue]报错如下:[/color]
org.springframework.web.util.NestedServletException: Hessian skeleton invocation failed; nested exception is 
com.caucho.hessian.io.HessianProtocolException:
.......
Caused by: com.caucho.hessian.io.HessianProtocolException: getList: expected end of call ('xxx') at 0x53 (S).
.....
com.caucho.hessian.client.HessianRuntimeException: com.caucho.hessian.io.HessianProtocolException:
.......


[color=blue]排查过程:[/color]
Caused by: com.caucho.hessian.io.HessianProtocolException: getList: expected end of call ('xxx') at 0x53 (S).
根据以下报错可以看出是调用getList方法时报错,将server端提供的接口反编译发现,getList存在多个,也就是存在重载的情况。

[color=blue]问题原因:[/color]
查找相关资料发现,Hessian的HessianFactory的isOverloadEnabled属性默认为false。这个参数如果为false,Hessian调用的时候获取接口仅根据方法名;反之,Hessian调用时决定调用哪个方法是通过方法名和参数类型一起决定。所以也就解释了,存在重载的方法时为什么会报以上错误。

[color=blue]解决办法:[/color]
在初始化HessianFactory对象时写在构造函数里,对factory设置 setOverloadEnabled(true) ,问题解决。


[color=red][size=large]3、Hessian由于版本不兼容导致的报错[/size][/color](com.caucho.hessian.io.HessianProtocolException: expected string at 0x6d )
报错如下:(借用了一下别人的报错信息,自己的忘记保存了。。。)
2011-4-25 16:14:44 org.apache.catalina.core.StandardWrapperValve invoke  
严重: Servlet.service() for servlet remoting threw exception
com.caucho.hessian.io.HessianProtocolException: expected string at 0x6d
at com.caucho.hessian.io.Hessian2Input.error(Hessian2Input.java:2882)
at com.caucho.hessian.io.Hessian2Input.expect(Hessian2Input.java:2830)
at com.caucho.hessian.io.Hessian2Input.readString(Hessian2Input.java:1362)
at com.caucho.hessian.io.Hessian2Input.readMethod(Hessian2Input.java:272)
at com.caucho.hessian.server.HessianSkeleton.invoke(HessianSkeleton.java:249)
at com.caucho.hessian.server.HessianSkeleton.invoke(HessianSkeleton.java:221)
at org.springframework.remoting.caucho.Hessian2SkeletonInvoker.invoke(Hessian2SkeletonInvoker.java:67)
at org.springframework.remoting.caucho.HessianServiceExporter.handleRequest(HessianServiceExporter.java:147)
at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:49)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:819)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:754)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:399)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:364)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:581)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)


[color=blue]排查过程:[/color]
这个报错真心花了好几个小时才搞定。。。从报错信息上来看,仅仅报出了expected string at 0x6d,这个信息没什么参考价值。。。但是我看了下面com.caucho.hessian.io.Hessian2Input.error(Hessian2Input.java:2882),为什么会出现Hessian2?带着疑问我去查了一下,发现高版本和低版本Hessian的协议已经变化了,低版本的是Hessian1,而高版本的是Hessian2。但是我管理的系统中Hessian版本和server端的版本一直没有变化呀,为什么会这样报错?突然想起来我resin的版本升级了,从3.0.28升级到了3.1,经过查询resin3.1新引入了Hessian的包,而且jar包的版本是高于我当前系统的低版本的,并且resin启动时会强制加载它的hessian包。。。orz。。。所以基本上定位了,就是版本不兼容。然而我还没发让server端更改高版本,所以只能自己想办法搞定这个事情。

[color=blue]问题原因:[/color]
Resin3.1引入的Hessian版本是高版本,其中使用的协议为Hessian2,而server端是低版本使用Hessian1协议,协议不匹配,通信后的结果自然是你不懂我我不懂你。

[color=blue]解决办法:[/color]
很多文章写解决办法都是换版本,但是在实际情况下,作为接口的使用者,没有能力更没有理由让server端按照你的意思去升级版本,但是这事就无解了吗?并不是,可以设置两个参数来解决这个事情。
factory.setHessian2Reply(false);
factory.setHessian2Request(false);
void setHessian2Reply(boolean isHessian2)
True if the proxy can read Hessian 2 responses.
void setHessian2Request(boolean isHessian2)
True if the proxy should send Hessian 2 requests.

根据Hessian的文档说明发现,这两个参数一个是设置用Hessian2协议发请求,一个是设置用Hessian2协议收回复,在高版本中这个参数默认是true,所以我们可以把它们设置成false,也就是通知系统强制用Hessian1协议来收发信息,问题也随之解决。(实验一段时间并未发现问题,目前看这个方案可行)


[color=darkred]总结:[/color]
以上就是这阶段系统中Hessian出现的各种问题的一个小总结,可能有些东西叙述起来略显啰嗦,也有可能某些东西存在问题,希望大家批评指正。
对于开源的软件来说,版本冲突的问题一直都是困扰程序猿的大问题,然而作为使用者的我们如何避免入坑呢?或许官方文档才是最值得依靠和研读的,即使它是英文的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值