NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity

报错信息:​​org.apache.http.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity​​ 解决方案:

public static InputStream getAsStream(String url) {
try (CloseableHttpClient client = HttpClients.createDefault();
CloseableHttpResponse response = client.execute(new HttpGet(url))) {
HttpEntity httpEntity = response.getEntity();
// 包装一层解决
BufferedHttpEntity bhe = new BufferedHttpEntity(httpEntity);
return bhe.getContent();
} catch (IOException e) {
LOGGER.error("doGet failed: " + e.getMessage());
}
return null;
}

参考:
​​​stackoverflow​

Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.

使用HttpClient,大量报出​​Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended​​的WARN日志,定位到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()可能带来的内存耗尽问题

解决方案,将stream转化为string:

private String convert(InputStream inputStream) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder sb = new StringBuilder();
String str;
while ((str = br.readLine()) != null) {
sb.append(str);
}
return sb.toString();
}

ConnectException: Connection refused

使用企业微信推送消息时遇到的问题,具体的报错信息:

java.lang.Exception: org.apache.http.conn.HttpHostConnectException: Connect to qyapi.weixin.qq.com:443 [qyapi.weixin.qq.com/81.69.87.29, qyapi.weixin.qq.com/81.69.54.213] failed: Connection refused
报错行
at com.xy.cloudiview.common.util.HttpUtil.doGet(HttpUtil.java:49)
at com.xy.cloudiview.common.util.SendWeChatUtil.getToken(SendWeChatUtil.java:193)
at com.xy.cloudiview.common.util.SendWeChatUtil.sendWeChat(SendWeChatUtil.java:57)
at com.xy.cloudiview.datasetsubscript.business.service.impl.TableWarnServiceImpl.sendWeChat(TableWarnServiceImpl.java:330)
at com.xy.cloudiview.datasetsubscript.business.service.impl.TableWarnServiceImpl.sendMsg(TableWarnServiceImpl.java:417)
at com.xy.cloudiview.datasetsubscript.business.service.impl.TableWarnServiceImpl.executeTableWarnJob(TableWarnServiceImpl.java:99)
at com.xy.cloudiview.datasetsubscript.business.xxljob.IviewTableWarnJobHandler.execute(IviewTableWarnJobHandler.java:45)
at com.ppdai.job.core.thread.JobThread.run(JobThread.java:142)
Caused by: org.apache.http.conn.HttpHostConnectException: Connect to qyapi.weixin.qq.com:443 [qyapi.weixin.qq.com/81.69.87.29, qyapi.weixin.qq.com/81.69.54.213] failed: Connection refused
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:156)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
at com.xy.cloudiview.common.util.HttpUtil.doGet(HttpUtil.java:39)
... 7 common frames omitted
Caused by: java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:368)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
... 17 common frames omitted

​HttpUtil.doGet​​方法定义:

public static String doGet(String url) throws Exception {
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
// 创建http GET请求
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = null;
String content = "";
try {
// 执行请求
response = httpclient.execute(httpGet);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
//请求体内容
content = EntityUtils.toString(response.getEntity(), "UTF-8");
} else {
log.error("doget error, url:{}, return code:{}", url,
response.getStatusLine().getStatusCode());
}
} catch (Exception e) {
// 报错行
throw new Exception(e);
} finally {
if (response != null) {
response.close();
}
//相当于关闭浏览器
httpclient.close();
}
return content;
}

没有什么意义的参考:

参考

  • ​​HttpClient警告​​