java http长链接(keep-alive)导致的问题

标签: java http 链接 | 发表时间:2020-02-21 11:01 | 作者:superbool
出处:https://juejin.im/welcome/backend

两种由http长链接(keep-alive)导致的问题,当然这两种问题都有多种原因导致,这里只分析针对keep-alive相关而产生的异常。

1 SocketException: Connection reset

报错堆栈日志:

  Caused by: java.net.SocketException: Connection reset
        at java.net.SocketInputStream.read(SocketInputStream.java:209)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
        at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
        at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:282)
        at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138)
        at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
        at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
        at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
        at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:165)
        at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
        at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
        at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
        at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
        at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
        at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
        at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:221)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:165)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:140)
复制代码

关于SocketException在官方文档有描述: docs.oracle.com/javase/8/do…

本质原因是 服务器通过TCP协议给客户端返回了RST消息,表示已经完成了发送和接收,如果客户端此时从流中读取数据时会发生Connection reset,往流中写数据时就会发生Connection reset Connection reset by peer。注意Socket.close()语义和TCP FIN消息之间略有不匹配。 而至于为什么服务端会返回 RST消息,那就是http keep-alive 导致的问题了。 如果是springboot的服务器,那么默认的keep-alive timeout是60s,如果客户端使用的是apache httpclient,默认的keep-alive是在 org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy类设置的,代码如下:

  public long getKeepAliveDuration(final HttpResponse response, final HttpContext context) {
        Args.notNull(response, "HTTP response");
        final HeaderElementIterator it = new BasicHeaderElementIterator(
                response.headerIterator(HTTP.CONN_KEEP_ALIVE));
        while (it.hasNext()) {
            final HeaderElement he = it.nextElement();
            final String param = he.getName();
            final String value = he.getValue();
            if (value != null && param.equalsIgnoreCase("timeout")) {
                try {
                    return Long.parseLong(value) * 1000;
                } catch(final NumberFormatException ignore) {
                }
            }
        }
        return -1;
    }
复制代码

可见,如果response header如果没有返回Keep-Alive,那么就会是-1,也就是无限的, hc.apache.org/httpcompone… "If the Keep-Alive header is not present in the response, HttpClient assumes the connection can be kept alive indefinitely"

所以问题就比较明白了,springboot服务端没有返回Keep-Alive的header,客户端如果使用了apache httpclient,且没有设置Keep-Alive的话,就会导致服务端的超时是60s,客户端就认为是无限的,在某些情况下,服务端关闭了链接,客户端还会获取这个连接,就会导致上面的问题。

既然找到原因了那么就需要解决,httpclient文档中也给了说要设置默认的超时时间,即给一个自定义的实现。

2 NoHttpResponseException: xxx.xxx.xxx.xxx failed to respond

  Caused by: org.apache.http.NoHttpResponseException: xxx.xxx.xxx.xxx failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:165)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:221)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:165)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:140)
复制代码

补充知识点:

1 'Connection: Keep-Alive' header头只用来在HTTP 1.0中, 而在HTTP 1.1中默认都是Keep-Alive的,所以不需要再添加'Connection: Keep-Alive'的头。所以在springboot1.5以上版本中,即使你在请求的header中加了'Connection: Keep-Alive'的头,在返回的header中是没有Connection的。相关链接: github.com/spring-proj…

2 curl 命令可以使用--http1.0 来强制走http1.0协议。

3 springboot中 tomcat 默认的keepalive timeout是60s, github.com/spring-proj…

相关 [java http 链接] 推荐:

java http长链接(keep-alive)导致的问题

- - 掘金后端
两种由http长链接(keep-alive)导致的问题,当然这两种问题都有多种原因导致,这里只分析针对keep-alive相关而产生的异常. at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:140) 复制代码.

HTTP长链接和短链接

- - Web前端 - ITeye博客
HTTP协议与TCP/IP协议的关系. HTTP的长连接和短连接本质上是TCP长连接和短连接. HTTP属于应用层协议,在传输层使用TCP协议,在网络层使用IP协议. IP协议主要解决网络路由和寻址问题,TCP协议主要解决如何在IP层之上可靠的传递数据包,使在网络上的另一端收到发端发出的所有包,并且顺序与发出顺序一致.

java JDBC 链接hive 操作实例

- - CSDN博客云计算推荐文章
1.在eclipse下面 导入包,简便方式 new ->mapred project -> 右键 ->选择“Properties”->Java Build Path->Library->Add External Jars 将/usr/hive/lib的所有jar包 添加上. (因为之前的配置 所有jar包 已经包括 java链接mysql的包).

[链接帖] 新的Java语言规范、Java虚拟机规范

- Wong - Script Ahead, Code Behind
随着7月28日,也就是Java SE 7预定的发布日期越来越近,相关的一些规范也已得到或即将得到批准. 这里主要关注的是下面几个规范:. Java语言规范,JSR 901的第三修订版(Maintenance Review 3)已经完成审核但尚未正式得到批准. Java虚拟机规范,JSR 924的第三修订版(Maintenance Review 3)在今年3月19日已经得到批准.

HTTP Headers 入门

- johnny - Time Machine
非常感谢 @ytzong 同学在twitter上推荐这篇文章,原文在此. 本文系统的对HTTP Headers进行了简明易懂的阐述,我仅稍作笔记. 什么是HTTP Headers. HTTP是“Hypertext Transfer Protocol”的所写,整个万维网都在使用这种协议,几乎你在浏览器里看到的大部分内容都是通过http协议来传输的,比如这篇文章.

HTTP基础

- - ITeye博客
HTTP的结构主要包括下面几个要点:. HTTP的版本主要有1.0,1.1 和更高版本.    1.1 及以上版本允许在一个TCP连接上传送多个HTTP协议,1.0能 .    1.1 及以上版本多个请求和响应可以重叠,1.0不能.    1.1 增加了很多的请求头和响应头.     一个请求行,若干小心头,以及实体内容,其中的一些消息头和实体内容是可选的,消息头和实体内容需要空行隔开.

HTTP Header 详解

- - 博客园_Ruby's Louvre
HTTP(HyperTextTransferProtocol)即超文本传输协议,目前网页传输的的通用协议. HTTP协议采用了请求/响应模型,浏览器或其他客户端发出请求,服务器给与响应. 就整个网络资源传输而言,包括message-header和message-body两部分. 首先传递message- header,即 http header消息.

HTTP/2 in Netty

- -
Here, we created a context for the server with a JDK SSL provider, added a couple of ciphers, and configured the Application-Layer Protocol Negotiation for HTTP/2..

HTTP负载测试

- - 博客 - 伯乐在线
英文原文: ON HTTP LOAD TESTING 来源: oschina. 有很多人在谈论HTTP服务器软件的性能测试,也许是因为现在有太多的服务器选择. 这很好,但是我看到有人很多基本相同的问题,使得测试结果的推论值得怀疑. 在日常工作中花费了很多时间在高性能代理缓存和源站性能测试方面之后,这里有我认为比较重要的一些方面来分享.

HTTP断点续传

- - CSDN博客互联网推荐文章
要实现断点续传的功能,通常都需要客户端记录下当前的下载进度,并在需要续传的时候通知服务端本次需要下载的内容片段. HTTP1.1协议(RFC2616)中定义了断点续传相关的HTTP头 Range和Content-Range字段,一个最简单的断点续传实现大概如下:.   1.客户端下载一个1024K的文件,已经下载了其中512K.