调用HttpClient.SendAsync发起请求时为何出现近7秒卡顿?
下载任务启动前卡顿7秒的排查方案
问题情况
代码托管于GitHub,点击下载按钮后应用不会冻结,但实际开始下载前会卡顿近7秒;第一个文件下载完成后,启动下一个文件前同样会卡顿约7秒,循环出现这个问题。下载功能本身正常,但卡顿原因不明。通过断点调试确认,卡顿发生在以下代码行:
HttpResponseMessage response = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
核心代码片段
public async Task StartDownload(CancellationToken cancellationToken = default) { var requestMessage = _requestMessageBuilder.Invoke(); long? totalFileSize = null; // 计算或获取总文件大小 if (totalFileSize.HasValue && totalFileSize <= 100 * 1024 * 1024) { if (requestMessage != null && requestMessage.RequestUri != null) { var streamingDownload = new StreamingDownloadWithProgress(_httpClient, _destinationFilePath); streamingDownload.ProgressChanged += (total, downloaded, progress) => ReportProgress(total, downloaded, progress); await streamingDownload.StartDownload(requestMessage.RequestUri, cancellationToken); } else { // 处理requestMessage或其RequestUri为null的情况 // 建议记录警告或抛出异常 } } else { HttpResponseMessage response = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, cancellationToken); await DownloadAsync(response, cancellationToken); } }
完整代码可查看对应文本内容。
排查与解决建议
- 检查DNS解析速度:用
nslookup或dig命令测试目标下载地址的域名解析耗时,如果解析慢,可更换公共DNS服务器(如1.1.1.1、8.8.8.8),或者在应用启动阶段提前预解析域名。 - 优化HttpClient连接池配置:默认的
SocketsHttpHandler会复用连接,但如果连接池资源耗尽或连接过期,会重新建立连接导致延迟。可以设置PooledConnectionLifetime为5分钟左右,调整MaxConnectionsPerServer参数,减少频繁新建连接的开销。 - 直接测试服务器响应:用
curl -I [目标下载URL]命令测试服务器返回响应头的耗时,如果这个操作本身就需要7秒,说明问题出在服务器端,需联系服务提供者优化。 - 排查代理/网络环境:如果当前使用了代理、VPN或内网网关,先关闭这类网络中间节点,测试是否是它们导致的延迟。
- 检查请求构建逻辑:确认
_requestMessageBuilder.Invoke()中没有同步阻塞的耗时操作,虽然断点卡在SendAsync,但请求构建阶段的阻塞也可能间接导致后续卡顿。
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

