HTTP客戶端警告:Going to buffer response body of large or unknown size
點關注不迷路,歡迎再訪!
精簡博客內容,盡量已行業術語來分享。
努力做到對每一位認可自己的讀者負責。
幫助別人的同時更是豐富自己的良機。
目錄
- HTTP客戶端警告:Going to buffer response body of large or unknown size
- 原編碼問題
- 源碼分析 getResponseBodyAsString()源碼
- getResponseBodyAsStream()源碼
- 優化原編碼
原編碼問題
HttpClient發現拋出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()方法源碼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 == -1L || contentLength > (long)limit),如果http頭沒有指定contentLength或大于上限值(默認1M),就會拋異常。其實,如果返回的結果比較確定,對程序沒有太大影響。而對于返回結果不確定時,源碼也建議我們使用下面的getResponseBodyAsStream()方法。
getResponseBodyAsStream()源碼
public InputStream getResponseBodyAsStream() throws IOException {if (this.responseStream != null) {return this.responseStream;} else if (this.responseBody != null) {InputStream byteResponseStream = new ByteArrayInputStream(this.responseBody);LOG.debug("re-creating response stream from byte array");return byteResponseStream;} else {return null;}}
從源碼中可以看出,getResponseBodyAsStream()內部沒有使用getResponseBody()方法,避免了內存耗盡問題,而是使用了InputStream流方式處理。
優化原編碼
HttpClient httpclient = new HttpClient();
GetMethod getMethod = new GetMethod(url);
int statusCode = httpclient.executeMethod(getMethod);
//String respContent = getMethod.getResponseBodyAsString();
//使用getResponseBodyAsStream()
InputStream inputStream = getMethod.getResponseBodyAsStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
StringBuffer stringBuffer = new StringBuffer();
String str = "";
while ((str = br.readLine()) != null) {stringBuffer.append(str);
}
LOGGER.info("respContent: {}", stringBuffer.toString());