使用HttpWebRequest调用Azure端点偶发连接失败,代码是否存在问题?
代码存在的核心问题
- HttpWebResponse资源未释放导致连接池耗尽
你代码中从GetRESTResponse返回的HttpWebResponse对象实现了IDisposable接口,但全程没有调用Dispose()或者用using包裹释放资源。.NET 中HttpWebRequest默认依赖系统连接池管理TCP连接,单域名默认最大连接数仅为2,当未释放的连接累计超过上限后,新的请求会在连接池排队等待空闲连接,排队超时就会抛出你遇到的连接失败错误,而且这种情况请求根本没有发出去,所以服务侧收不到请求记录,完全符合你描述的现象。 - 请求流未做安全释放
GetRESTResponse方法中写入请求体的Stream dataStream仅在正常执行时调用了Close(),如果写入过程中抛出异常,Close()逻辑不会执行,会额外占用资源。 - 编码使用不规范
序列化请求体时用了Encoding.Default,这个编码取决于运行程序的系统默认配置,发application/json格式请求应该统一用Encoding.UTF8,避免乱码导致的服务端解析失败。 - 拼写错误
catch (WebException e)块中打日志的e.Reponse拼写错误,正确为e.Response,会导致异常日志收集不全。
修复方案
- 所有用到
HttpWebResponse的地方都用using包裹,确保资源释放,修改SingleRead方法:
public T SingleRead<T>(string url, string method, object entity = null) { T returnValue = default(T); using (var resp = GetRESTResponse(url, method, entity)) { string responseText = GetResponseText(resp); try { returnValue = JsonConvert.DeserializeObject<T>(responseText); } catch (Exception ex) { return default(T); } } return returnValue; }
- 请求流用
using包裹自动释放,不需要手动调用Flush和Close,修改GetRESTResponse里的请求体写入逻辑:
if (entity != null) { byte[] byteArray = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(entity)); req.ContentLength = byteArray.Length; req.ContentType = "application/json"; using (Stream dataStream = req.GetRequestStream()) { dataStream.Write(byteArray, 0, byteArray.Length); } }
- 可以适当调高连接池上限,在程序启动时添加配置,数值根据实际并发请求量调整即可:
ServicePointManager.DefaultConnectionLimit = 512;
- 长期迭代建议替换为
HttpClient静态单例实现,这是.NET官方现在推荐的HTTP请求实现,不需要手动管理连接释放,天然避免连接池耗尽问题,性能和稳定性都优于HttpWebRequest。
内容的提问来源于stack exchange,提问作者markzzz
相关产品推荐
相关产品推荐

