有反向代理(Nginx)时Hessian的411错误解决方案

来源:互联网 发布:王源同款衣服淘宝 编辑:程序博客网 时间:2024/04/30 19:03

 

 

 

有反向代理(Nginx)时Hessian411错误解决方案

 

问题描述:

Hessian实现web service过程中,需要创建对象时,是使用HTTP POST方法来传递数据的。但是在有反向代理(nginx)的情况下,会抛出异常(com.caucho.hessian.client.HessianConnectionException:411:java.io.IOException: Server returned HTTP response code: 411 forURL:http://xxxx/xxx/xxxService)

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

 

解决方法:

com.caucho.hessian.client.HessianProxyFactory类中,有一个boolean _chunckedPost的域成员,其默认值为true。这个值就是规定Hessian是否以分块发送的方式与服务端交换数据的参数,因此在创建com.caucho.hessian.client.HessianProxyFactory的对象后(假设为factory),只要调用其上的setChunckedPost()方法,把这个属性设置为false即可。即factory.setChunkedPost(false);

 

分块编码传输:

分块编码(chunked encoding)传输方式是HTTP 1.1协议中定义的Web用户向服务器提交数据的一种方法,当服务器收到chunked编码方式的数据时会分配一个缓冲区存放之,如果提交的数据大小未知,客户端会以一个协商好的分块大小向服务器提交数据。

 

The content canbe broken up into a number of chunks; each of which is prefixed by its size inbytes. A zero size chunk indicates the end of the response message. If a serveris using chunked encoding it must set the Transfer-Encoding header to"chunked".

Chunked encodingis useful when a large amount of data is being returned to the client and thetotal size of the response may not be known until the request has been fullyprocessed. An example of this is generating an HTML table of results from adatabase query. If you wanted to use the Content-Length header you would haveto buffer the whole result set before calculating the total content size. However,with chunked encoding you could just write the data one row at a time and writea zero sized chunk when the end of the query was reached.

        

如果不使用Chunked encoding传输方式,需要将要发送的数据缓存下来,计算出content-length,从而满足反向代理(Nginx)需要content-length的要求。

                  

 

 

 

业务系统对hessian进行封装:

1.       根据HessianProxyFactoryBean实现MyHessianProxyFactoryBean

 

public class MyHessianProxyFactoryBean extendsMyHessianClientInterceptor implements FactoryBean{

 

    private Object serviceProxy;

 

    public void afterPropertiesSet() {

        super.afterPropertiesSet();

        this.serviceProxy = new ProxyFactory(getServiceInterface(), this)

               .getProxy(getBeanClassLoader());

    }

 

    public Object getObject() {

        return this.serviceProxy;

    }

 

    public Class getObjectType() {

        returngetServiceInterface();

    }

 

    public boolean isSingleton() {

        return true;

    }

}

 

2.       根据HessianClientInterceptor实现MyHessianClientInterceptor

 

public class MyHessianClientInterceptor extends UrlBasedRemoteAccessor implementsMethodInterceptor {

 

    private HessianProxyFactory proxyFactory = newMyHessianProxyFactory();

 

private Object hessianProxy;

 

……………………

}

3.       继承HessianProxyFactory实现MyHessianProxyFactory

 

 

public class MyHessianProxyFactory extends HessianProxyFactory {

 

    @Override

    public Object create(Classapi, String urlName, ClassLoader loader)

            throws MalformedURLException {

        this.setChunkedPost(false); //设置规定Hessian不以分块发送的方式与服务端交换数据,解决hessiannginx411错误

 

        if (api == null) throw new NullPointerException(

                "api must not be null for HessianProxyFactory.create()");

        InvocationHandler handler = null;

 

        URL url = new URL(urlName);

        handler = new MyHessianProxy(url, this);

 

        return Proxy.newProxyInstance(loader,new Class[] { api, HessianRemoteObject.class },

                handler);

    }

 

}

4.       继承HessianProxy实现MyHessianProxy

public class MyHessianProxyextends HessianProxy {

 

    public MyHessianProxy(URL url,HessianProxyFactory factory) {

        super(url, factory);

    }

 

    /** Getinformation from the headers of response */

    @Override

    protected void parseResponseHeaders(URLConnection conn) {

 

    }

 

    /** Addinformation to request headers */

    @Override

    protected void addRequestHeaders(URLConnection conn) {

 

    }

 

}

 

 

 

针对该问题的简单配置:

         xml配置文件中添加属性:

<property name="chunkedPost">

           <value>false</value>

       </property>

 

       <property name="readTimeout">

           <value>25000</value>

       </property>

 

总结:

         该问题还可以通过修改nginx配置,使得nginx可以处理分块编码(chunked encoding)传输方式。据本人所知,nginx还没有明确的解决方案,需要继续研究。

         Hessian扩展性很好,它的实现预留了一些接口,允许开发人员对其进行一定的封装,从而按自己的需求对hessian进行设置。

原创粉丝点击