IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> HTTP请求超时,到底发生了什么? -> 正文阅读

[网络协议]HTTP请求超时,到底发生了什么?

客户老是反应调用我们接口超时,但通过监控来看系统并没有什么异常,所以接口调用超时时到底发生了什么呢?让我们通过本文来一探究竟。

1 模拟一下调用超时

服务端程序(一个简单的REST接口,直接睡眠个10s,模拟响应时间长):

@RestController
public class HelloController {

    @GetMapping("hello")
    public String hello() throws InterruptedException {
        System.out.println("开始处理");
        Thread.sleep(10000);
        System.out.println("处理结束");
        return "hello";
    }
}

客户端程序(通过HttpClient调用REST接口,配置socketTimeout参数,将超时时间设置为2s):

@Test
public void testHttpClientTimeout() throws IOException {
    try(CloseableHttpClient httpClient = HttpClients.createDefault()) {
        HttpGet httpGet = new HttpGet("http://localhost:8080/hello");
        httpGet.setConfig(RequestConfig.custom().setConnectTimeout(10 * 1000).setSocketTimeout(2 * 1000).build());
        try(CloseableHttpResponse response = httpClient.execute(httpGet)) {
            EntityUtils.toString(response.getEntity());
        }
    }
}

启动服务端,然后客户端发起调用。

客户端在2s后发生超时,调用终止:

java.net.SocketTimeoutException: Read timed out

服务端接口打印日志:

开始处理
处理结束

由上述日志可以看出,客户端调用在超过2s后还没有获得响应时,便会抛出Read timed out异常,结束调用,但是服务端针对本次调用还是会完整的处理完,不会因为客户端的调用终止而终止处理。

所以这期间到底发生了什么?服务端请求处理完成后还能响应给客户端吗?

2 刨根问题:调用超时到底发生了什么?

重复上述步骤,模拟客户端调用超时,进行抓包。

抓取的数据包如下:

接口调用超时数据包

根据抓包得出整个处理流程如下:
1、TCP三次握手;
2、客户端发起请求;
3、2s后,客户端请求超时,发送FIN包关闭连接;
4、服务端响应FIN包,返回ACK;
5、10s后,服务端处理完请求,返回响应;
6、客户端响应RST重置连接。

可以看到,即使客户端已经返回响应超时异常了,服务端还是会正常处理请求并在完成后响应,并且这个请求状态还是200(这也是服务端监控并没有发现响应异常的原因),但是在返回响应给客户端时,客户端会响应RST包重置该连接,也就是该响应最终并没有成功返回给客户端。

所以说,HTTP请求超时是客户端调用方的概念,服务端在处理请求的过程中不会因为处理时间过长而中断响应,反而是会一直等待请求处理完成然后返回客户端。

至此,接口请求超时的整个处理流程应该比较清楚了。

但还有一个问题,客户端是怎么触发超时提前抛出异常返回的呢?

首先看超时配置:

httpGet.setConfig(RequestConfig.custom().setConnectTimeout(10 * 1000).setSocketTimeout(2 * 1000).

可以看到上述设置了超时时间参数socketTimeout,通过跟代码,该参数实际是设置了Socket连接的soTimeout参数:

设置Socket的soTimeout参数

继续看Socket#setSoTimeout方法,通过注释该参数的意思应该比较清楚了——如果超过设置的超时时间读操作还没有返回(即没有接收到响应数据),则会抛出SocketTimeoutException异常。

设置Socket的soTimeout参数

所以客户端的请求超时实际上是通过设置Socket#soTimeout参数来实现的,即超过指定时间还未读到响应数据,则抛出异常。

写在最后

HTTP请求超时是客户端调用方的概念。

服务端在处理请求的过程中不会因为处理时间过长而中断响应,反而是会一直等待请求处理完成然后返回客户端。

客户端在调用超时后,会发送FIN包中断连接,所以即使服务端处理完请求后,也无法正确返回给客户端。

客户端的请求超时实际上是通过设置Socket#soTimeout参数来实现的。

知道了这么多,那么到底该如何解决客户端调用超时的问题呢?客户端调用超时的根本原因还是服务端响应过慢,解决方法得从提升服务端性能,减少响应时间入手。如果服务端涉及到第三方调用,还需要将同步调用异步化,通过牺牲一致性来提升性能。

希望今天的内容对大家有所帮助,更多精彩文章欢迎关注微信公众号:WU双。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-10-12 23:49:56  更:2021-10-12 23:52:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:53:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码