是否需要释放HttpResponseMessage与HttpRequestMessage?附代码示例
关于HttpClient中HttpResponseMessage的释放与代码最佳实践
咱们先把这个问题拆成两部分说清楚——首先是HttpResponseMessage/HttpRequestMessage的释放规则,再看你给出的代码存在的问题:
一、先搞懂什么时候需要释放
- HttpRequestMessage:如果你是手动
new出来的(比如自定义请求头、请求内容时),那必须用using包裹或者手动调用Dispose(),因为它实现了IDisposable接口。但像你用的HttpClient.GetAsync()这类快捷方法,内部会自动创建并释放对应的HttpRequestMessage,完全不用你操心。 - HttpResponseMessage:它同样实现了
IDisposable,而且调用它的Dispose()时会自动释放关联的HttpContent。但这里有个关键坑:如果你需要把HttpResponseMessage返回给上层调用,绝对不能用using包裹它——using块结束时会自动调用Dispose(),上层拿到的就是一个已被释放的对象,再操作就会抛出ObjectDisposedException。
二、你的代码存在的问题
- 错误的
using包裹:你把messageResponse放在using里,但最后又把它包装进MyWrapperResponse返回了,这会导致返回的messageResponse已经被释放,上层调用时必然报错。 - 没必要的
Task.Run:JsonConvert.DeserializeObject是同步方法,用Task.Run把它丢去线程池完全是多此一举,反而会增加线程调度的开销,直接调用就行。
三、修改后的最佳实践代码
// httpClient已通过HttpClientFactory注入 var messageResponse = await httpClient.GetAsync(uri, cancellationToken).ConfigureAwait(false); try { if (messageResponse.IsSuccessStatusCode) { var json = await messageResponse.Content.ReadAsStringAsync().ConfigureAwait(false); // 直接反序列化,不用包Task.Run var response = JsonConvert.DeserializeObject<TResponse>(json, serializerSettings); return new MyWrapperResponse<TResponse>(messageResponse, response); } else { // 非成功状态下,我们不需要返回response,手动释放 messageResponse.Dispose(); throw new HttpRequestException($"请求失败,状态码:{messageResponse.StatusCode}"); } } catch { // 发生异常时,确保response被释放,再重新抛出异常 messageResponse.Dispose(); throw; }
另外补充一个重要细节:因为你把messageResponse返回给了上层,释放它的责任就转移到了上层。建议让你的MyWrapperResponse<TResponse>实现IDisposable接口,在它的Dispose()方法里调用messageResponse.Dispose(),这样上层用using包裹MyWrapperResponse时,就能自动释放内部的HttpResponseMessage,避免资源泄漏。
内容的提问来源于stack exchange,提问作者developer9969
相关产品推荐
相关产品推荐

