欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

服务器使用Gzip压缩JSON数据报“socket write error: Connection reset by peer.”错误 博客分类: java web开发 GzipJSONConnection reset by peer 

程序员文章站 2024-03-24 15:08:52
...

        现有服务器部署及问题出现点:

服务器使用Gzip压缩JSON数据报“socket write error: Connection reset by peer.”错误
            
    
    博客分类: java web开发 GzipJSONConnection reset by peer 
原因分析:

        JsonDispatherHandler对response.getWriter()进行write和flush方法后,response.getWriter()就被Web服务器关闭了,这样在过滤器中去获取输出流并writer时,就会抛出Connection reset by peer的错误。

 

解决方法:

        新建JsonDispatcherHandlerWithGzip.java,继承JsonDispatherHandler对相应方法进行重写,并修改配置文件,将配置文件相关配置都改成JsonDispatcherHandlerWithGzip.java。

public class JsonDispatcherHandlerWithGzip extends JsonDispatcherHandler {
	
    public final static String RESULT = "JsonView4WebDispatcherHandler_result";
    private static final String NULL_JSON_STRING = "{}";
    private String defaultContentType = "text/html";

    @Override
    protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        long startTime = System.currentTimeMillis();
        addResponseHeader(response);
        byte[] bytes = (byte[]) model.get(RESULT);
        if (isGZipEncoding(request)) {
            byte[] outData = null;
            if (bytes.length > 512) {
                byte[] gzipData = toGzipBytes(bytes);
                response.setHeader("Content-Encoding", "gzip");
                response.setHeader("Transfer-Encoding", "");
                response.setContentLength(gzipData.length);
                outData = gzipData;
                PASLogUtils.debugTrace("gzip end ,cost:" + (System.currentTimeMillis() - startTime));
            } else {
                outData = bytes.length == 0 ? NULL_JSON_STRING.getBytes(response.getCharacterEncoding()):bytes;
            }
            ServletOutputStream output = response.getOutputStream();
            output.write(outData);
            output.flush();
        }else{
            String resp = bytes.length == 0 ? NULL_JSON_STRING : new String(bytes, response.getCharacterEncoding());
            PASLogUtils.debugTrace("Rest result =" + resp);
            Writer out = response.getWriter();        
            out.write(resp);
            out.flush();
        }
    }

    /*
     * 增加响应头信息 
     */
    private void addResponseHeader(HttpServletResponse response) {
        if (!StringUtils.hasText(response.getContentType())) {
            StringBuffer contentTypeBuffer = new StringBuffer();
            contentTypeBuffer.append(defaultContentType);
            contentTypeBuffer.append(";charset=" + response.getCharacterEncoding());
            response.setContentType(contentTypeBuffer.toString());
        }
    }
    /*
     * 判断浏览器是否支持GZIP
     */
    private boolean isGZipEncoding(HttpServletRequest request) {
        boolean flag = false;
        String encoding = request.getHeader("Accept-Encoding");
        if (encoding.indexOf("gzip") != -1) {
            flag = true;
        }
        return flag;
    }
    
    public static byte[] toGzipBytes(byte[] srcData) {
        if (srcData == null || srcData.length == 0) {
            return null;
        }
        
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        
        GZIPOutputStream gzip = null;
        try {
            gzip = new GZIPOutputStream(out);
            gzip.write(srcData);
        } catch (IOException e) {
            PASLogUtils.debugErorr(e.getMessage());
        } finally {
            if (gzip != null) {
                try {
                    gzip.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return out.toByteArray();
    }
}

        这样问题就解决了。特别注意response.setHeader("Transfer-Encoding", "");这条语句,Transfer-Encoding: chunked表示输出的内容长度不能确定,普通的静态页面、图片之类的基本上都用不到这个。详细可以参见http://bijian1013.iteye.com/blog/2280945

        在这我特意做了如下测试:

        1.将response.setHeader("Transfer-Encoding", "");这条语句去掉,请求后台都没有报错,但浏览器未能正常展示,分析发现是因为实际返回到浏览器的长度和Content-Length长度不一致导致浏览器未能正确解析。

服务器使用Gzip压缩JSON数据报“socket write error: Connection reset by peer.”错误
            
    
    博客分类: java web开发 GzipJSONConnection reset by peer 
        2.将response.setHeader("Transfer-Encoding", "");改成将response.setHeader("Transfer-Encoding", "chunked");报“Could not complete request java.net.SocketException: Connection reset by peer: socket write error”错。

        3.而如果将response.setHeader("Transfer-Encoding", "");和response.setContentLength(gzipData.length);这两条语句都去掉,就能正常。此时用http Watch看到信息如下:

服务器使用Gzip压缩JSON数据报“socket write error: Connection reset by peer.”错误
            
    
    博客分类: java web开发 GzipJSONConnection reset by peer 
服务器使用Gzip压缩JSON数据报“socket write error: Connection reset by peer.”错误
            
    
    博客分类: java web开发 GzipJSONConnection reset by peer 

  • 服务器使用Gzip压缩JSON数据报“socket write error: Connection reset by peer.”错误
            
    
    博客分类: java web开发 GzipJSONConnection reset by peer 
  • 大小: 16 KB
  • 服务器使用Gzip压缩JSON数据报“socket write error: Connection reset by peer.”错误
            
    
    博客分类: java web开发 GzipJSONConnection reset by peer 
  • 大小: 15.2 KB
  • 服务器使用Gzip压缩JSON数据报“socket write error: Connection reset by peer.”错误
            
    
    博客分类: java web开发 GzipJSONConnection reset by peer 
  • 大小: 11.5 KB
  • 服务器使用Gzip压缩JSON数据报“socket write error: Connection reset by peer.”错误
            
    
    博客分类: java web开发 GzipJSONConnection reset by peer 
  • 大小: 10.4 KB