ASP.NET Core Web API调用出现net::ERR_CONNECTION_RESET 200错误如何解决
问题根因分析
为什么添加断点时运行正常、无断点时就报错
你遇到的net::ERR_CONNECTION_RESET 200 (OK)错误本质是服务端在返回HTTP 200响应的过程中主动断开了TCP连接,核心原因有3个:
- 存在竞态条件:
PaymentStatusCheckUsingAPI方法中使用的resJson没有在方法内部声明,若为类成员变量,多请求并发时会共享该变量,无断点时请求并行处理,可能出现resJson还未完成赋值就被返回、甚至赋值冲突的问题;加断点时请求被人为暂停,串行执行有足够时间完成完整赋值流程,不会触发该问题。 - 同步IO导致连接泄漏/线程阻塞:
PostPaymentRequestToGateway方法中使用WebRequest的同步方法GetRequestStream()、GetResponse(),会阻塞线程且连接资源未正确释放,无断点时请求处理速度快,连接池耗尽后服务端会强制关闭超时请求的连接;加断点时人为增加了请求间隔,连接有足够时间释放复用,不会出现资源耗尽的问题。 - 逻辑判断错误:
GetResponseMap方法中判断message有效性的逻辑是if (message != null || !"".Equals(message)),或运算下若message为null,仍然会进入分支执行message.Split('&')抛出空引用异常,未被捕获的异常会让ASP.NET Core直接终止响应、关闭连接;加断点时网关响应已返回,message有有效值,不会触发该异常。
现有异步实现的错误点
你的异步实现不符合全链路异步的最佳实践,存在多个问题:
- 异步方法混用同步IO:
PostPaymentRequestToGateway标记了async,但核心的请求发送、响应获取都是同步阻塞方法,并没有真正实现异步,反而会增加线程上下文切换的开销,容易引发线程池饥饿。 - 不必要的异步包装:
GetResponseMap方法没有任何异步IO操作,不需要标记async,用Task.FromResult包装返回值属于多余操作,会增加不必要的性能开销。 - 资源未正确释放:
WebRequest、StreamWriter、HttpWebResponse等实现了IDisposable接口的对象都没有做资源释放,会导致TCP连接泄漏,占用系统资源。 - 隐式转换风险:
GetPaymentStatus方法返回类型为IBaseResult<string>,但直接返回string类型的apiResponse,依赖隐式转换,转换失败时会直接抛出运行时异常。
修复方案
步骤1:修正基础逻辑错误
- 在
PaymentStatusCheckUsingAPI方法内部声明resJson变量,避免多线程共享成员变量引发的竞态问题。 - 修正
GetResponseMap的有效性判断,直接使用string.IsNullOrEmpty简化逻辑,同时移除不必要的异步包装。 - 增加异常捕获和处理,避免未处理异常导致服务端主动断开连接。
步骤2:全链路异步改造
推荐替换老旧的WebRequest为微软官方推荐的HttpClient(建议注入单例HttpClient实例使用,不要每次请求都新建),以下是修改后的代码示例:
// 修正后的GetResponseMap,移除多余async private NameValueCollection GetResponseMap(string message) { NameValueCollection Params = new NameValueCollection(); if (!string.IsNullOrEmpty(message)) { string[] segments = message.Split('&'); foreach (string seg in segments) { string[] parts = seg.Split('='); if (parts.Length >= 2) { string Key = parts[0].Trim(); string Value = parts[1].Trim(); Params.Add(Key, Value); } } } return Params; } // 替换WebRequest为HttpClient的异步实现,_httpClient为注入的单例实例 private async Task<string> PostPaymentRequestToGateway(string queryUrl, string urlParam) { string message = ""; try { var content = new StringContent(urlParam, Encoding.UTF8, "application/x-www-form-urlencoded"); var response = await _httpClient.PostAsync(queryUrl, content); response.EnsureSuccessStatusCode(); message = await response.Content.ReadAsStringAsync(); } catch (Exception exception) { Console.WriteLine("Exception occurred while connection." + exception); // 可根据业务需要抛出异常,避免后续逻辑处理空值 } return message; } // 修正后的PaymentStatusCheckUsingAPI private async Task<string> PaymentStatusCheckUsingAPI(string orderNumber) { string message = await PostPaymentRequestToGateway(statusApiUrl, authQueryUrlParam); NameValueCollection param = GetResponseMap(message); // 方法内部声明resJson,避免多线程竞态 string resJson = ""; string status = ""; string encResJson = ""; if (param != null && param.Count == 2) { status = param["status"]; encResJson = param["enc_response"]; if (status == "0") { resJson = crypto.Decrypt(encResJson, workingKey); } else if (status == "1") { Console.WriteLine("failure response: " + encResJson); } } return resJson; } // 修正返回值转换问题 public async Task<IBaseResult<string>> GetPaymentStatus(PaymentSearchModel requestModel) { string apiResponse = await PaymentStatusCheckUsingAPI(requestModel.orderid); // 显式构造返回对象,避免隐式转换风险 return new BaseResult<string> { success = !string.IsNullOrEmpty(apiResponse), Data = apiResponse }; }
步骤3:补充服务端异常处理
可在Web API层添加全局异常过滤器,所有未捕获的异常统一返回标准错误响应,避免服务端直接断开连接导致前端出现ERR_CONNECTION_RESET错误。
内容的提问来源于stack exchange,提问作者Nithin Paul
相关产品推荐
相关产品推荐

