使用HttpClient时如何避免NetworkStream已释放异常?
问题根源
这个异常大多是因为提前释放了HttpClient实例,或者HttpClient底层连接池清理闲置连接时,内部线程尝试访问已经被释放的NetworkStream导致的。默认情况下,HttpClient的连接池会保留闲置连接一段时间(不同版本时长略有差异,大概2分钟左右),要是在连接池还在维护连接的时候就Dispose了HttpClient,就会触发这个异常。
具体解决办法
复用HttpClient实例,别频繁创建和销毁
别每次请求都用using (var client = new HttpClient()) { ... }这种写法,HttpClient本身就是设计成可复用的单例/静态实例。比如:// 全局复用的实例 private static readonly HttpClient _httpClient = new HttpClient(); // 调用代码 public async Task<string> GetDataAsync() { var response = await _httpClient.GetAsync("https://example.com"); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); }要是用的是.NET Core/.NET 5+,更推荐用
IHttpClientFactory来管理HttpClient,它会自动处理连接池和实例生命周期,不用自己操心:// 先把HttpClient注册到DI容器 services.AddHttpClient(); // 注入后直接用 private readonly HttpClient _httpClient; public MyService(HttpClient httpClient) { _httpClient = httpClient; }调整连接池闲置超时
如果确实需要短时间内释放HttpClient,可以调整连接池的闲置超时,让连接在Dispose之前就被清理掉:var handler = new HttpClientHandler(); // 把闲置连接超时设为30秒 handler.IdleConnectionTimeout = TimeSpan.FromSeconds(30); using (var client = new HttpClient(handler)) { // 执行请求逻辑 var response = await client.GetAsync("https://example.com"); }也可以修改全局的ServicePointManager设置,影响所有HttpClient实例:
// 设置所有服务点的闲置超时为30秒(单位毫秒) ServicePointManager.MaxServicePointIdleTime = 30000;升级.NET框架版本
一些旧版本的.NET(比如.NET Framework 4.6.x之前)存在HttpClient连接池的已知Bug,升级到最新稳定版本大概率能解决这类问题。
是不是框架Bug?
大部分情况下这个异常是使用方式不对导致的,不是框架Bug。但如果已经正确复用了HttpClient实例,还是出现这个异常,那可能是特定版本框架的Bug,建议检查你的.NET版本并升级,也可以去dotnet/runtime的GitHub仓库搜相关Issue确认。
内容的提问来源于stack exchange,提问作者Undead

