httpClient笔记

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;
}

没有什么意义的参考:

参考

posted @   johnny233  阅读(74)  评论(0编辑  收藏  举报  
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示