跳到主要内容

使用Httpclient报Going To Buffer Response Body Of Large Or Unknown Size. Using Getresponsebodyasstream Instead Is

·1069 字·3 分钟

使用HttpClient报Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.警告处理

使用如下代码利用HttpClient获取服务器上附件时,报出警告:WARN org.apache.commons.httpclient.HttpMethodBase - Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.的WARN日志。

public String fileToBase64(String fileSrc){
        String externalPath = "";
        String result = "";
        String[] typeArr = fileSrc.split("\\.");
        int num = typeArr.length-1;
        String type = typeArr[num];

        //通过http访问外网电子档案服务
        HttpClient httpClient = new HttpClient();
        httpClient.getHostConfiguration().setHost("127.0.0.1", 8080, "http");//外网dossier服务地址、端口、访问方式
        HttpMethod method;
        byte[] a = null;
        try {
            method = getMethod("/anarkh/dossier/upload/images/"+fileSrc);
            httpClient.executeMethod(method);
            a =  method.getResponseBody();
            BASE64Encoder encoder = new BASE64Encoder();
            if("jpg".equals(type)||"png".equals(type)||"bmp".equals(type){
                result = encoder.encode(a) ;
            }
            method.releaseConnection();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
}
private static HttpMethod getMethod(String url) throws IOException {
        GetMethod get = new GetMethod(url);
        get.addRequestHeader("Accept","application/json;charset=UTF-8");
        get.releaseConnection();
        return get;
}    
    

定位到HttpClient的源码如下:

public abstract class HttpMethodBase
    implements HttpMethod
{
...
    public byte[] getResponseBody() throws IOException {
        if (responseBody == null) {
            InputStream instream = getResponseBodyAsStream();
            if (instream != null) {
                long contentLength = getResponseContentLength();
                if (contentLength > 2147483647L){
                    throw new IOException("Content too large to be buffered: " + contentLength + " bytes");          }
                int limit = getParams().getIntParameter("http.method.response.buffer.warnlimit", 1048576);
                if (contentLength == -1L || contentLength > (long) limit){
                    LOG.warn("Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.");          }
                LOG.debug("Buffering response body");
                ByteArrayOutputStream outstream = new ByteArrayOutputStream(contentLength <= 0L ? 4096: (int) contentLength);
                byte buffer[] = new byte[4096];
                int len;
                while ((len = instream.read(buffer) > 0){            outstream.write(buffer, 0, len);          }
                outstream.close();
                setResponseStream(null);
                responseBody = outstream.toByteArray();
            }
        }
        return responseBody;
    }
...
}

报WARN的条件是((contentLength == -1) || (contentLength > limit),也就是说,或者是返回的HTTP头没有指定contentLength,或者是contentLength大于上限(默认是1M)。如果能确定返回结果的大小对程序没有显著影响,这个WARN就可以忽略,可以在日志的配置中把HttpClient的日志级别调到ERROR,不让它报出来。

当然,这个警告也是有意义的,HttpClient建议使用InputStream getResponseBodyAsStream()代替byte[] getResponseBody()。对于返回结果很大或无法预知的情况,就需要使用InputStreamgetResponseBodyAsStream(),避免byte[] getResponseBody()可能带来的内存的耗尽问题。

修改代码如下解决问题:

public String fileToBase64(String fileSrc){
        String externalPath = "";
        String result = "";
        String[] typeArr = fileSrc.split("\\.");
        int num = typeArr.length-1;
        String type = typeArr[num];
        //获取接口地址
        StringBuffer sb = new StringBuffer("select aaa004 from AA01 where aaa001 = 'SI_External_Dossier'");
        Query q = em.createNativeQuery(sb.toString();
        List list = q.getResultList();
        externalPath =  list.get(0).toString();//应该return
//        result = externalPath + fileSrc;
        String[] externalPathArray = externalPath.split(",");

        //通过http访问外网电子档案服务
        HttpClient httpClient = new HttpClient();
        httpClient.getHostConfiguration().setHost(externalPathArray[0], Integer.parseInt(externalPathArray[1]), externalPathArray[2]);//外网dossier服务地址、端口、访问方式
        HttpMethod method;
        byte[] buffer = new byte[1024*4];
        InputStream input = null;
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        try {
            method = getMethod(externalPathArray[3]+fileSrc);
            httpClient.executeMethod(method);
            input = method.getResponseBodyAsStream();
            int n = 0;
            while (-1 != (n = input.read(buffer)) {
                output.write(buffer, 0, n);
            }
            BASE64Encoder encoder = new BASE64Encoder();
            if("jpg".equals(type)||"png".equals(type)||"bmp".equals(type){
                result = encoder.encode(output.toByteArray() ;
            }
            method.releaseConnection();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (output != null) {
                    output.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (input != null) {
                    input.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
}
private static HttpMethod getMethod(String url) throws IOException {
        GetMethod get = new GetMethod(url);
        get.addRequestHeader("Accept","application/json;charset=UTF-8");
        get.releaseConnection();
        return get;
}