在修复原有代码bug时,发现日志里经常抛出Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended,这种提示。查看了原有代码中的逻辑如下:
... ...
HttpClient httpclient = new HttpClient();
GetMethod getMethod = new GetMethod(url);
int statusCode = httpclient.executeMethod(getMethod);
String respContent = getMethod.getResponseBodyAsString();
... ...
原因就在于使用了getResponseBodyAsString()
方法
源码分析
getResponseBodyAsString()源码
//getResponseBodyAsString()方法源码
public String getResponseBodyAsString() throws IOException {
byte[] rawdata = null;
if (this.responseAvailable()) {
//调用了getResponseBody(),容易消耗内存
rawdata = this.getResponseBody();
}
return rawdata != null ? EncodingUtil.getString(rawdata, this.getResponseCharSet()) : null;
}
//responseAvailable()方法源码
private boolean responseAvailable() {
return this.responseBody != null || this.responseStream != null;
}
//getResponseBody()方法源码
public byte[] getResponseBody() throws IOException {
if (this.responseBody == null) {
InputStream instream = this.getResponseBodyAsStream();
if (instream != null) {
long contentLength = this.getResponseContentLength();
if (contentLength > 2147483647L) {
throw new IOException("Content too large to be buffered: " + contentLength + " bytes");
}
int limit = this.getParams().getIntParameter("http.method.response.buffer.warnlimit", 1048576);
if (contentLength == -1L || contentLength > (long)limit) {
//这里是warn的原文
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 ? (int)contentLength : 4096);
byte[] buffer = new byte[4096];
int len;
while((len = instream.read(buffer)) > 0) {
outstream.write(buffer, 0, len);
}
outstream.close();
this.setResponseStream((InputStream)null);
this.responseBody = outstream.toByteArray();
}
}
return this.responseBody;
}
报WARN的条件是((contentLength == -1) || (contentLength> limit)),也就是说,或者是返回的HTTP头没有指定contentLength,或者是contentLength大于上限(默认是1M)。如果能确定返回结果的大小对程序没有显著影响,这个WARN就可以忽略,可以在日志的配置中把HttpClient的日志级别调到ERROR,不让它报出来。
当然,这个警告也是有意义的,HttpClient建议使用InputStream getResponseBodyAsStream()代替byte[]getResponseBody()。对于返回结果很大或无法预知的情况,就需要使用InputStreamgetResponseBodyAsStream(),避免byte[] getResponseBody()可能带来的内存的耗尽问题。
如果返回的头信息没有指定长度或长度大于1M则抛出如上异常。
则需把 getResponseBodyAsString()换成 getResponseBodyAsStream()即可
InputStream inputStream = method.getResponseBodyAsStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
StringBuffer stringBuffer = new StringBuffer();
String str= "";
while((str = br.readLine()) != null){
stringBuffer .append(str);
}