.NET Framework下HttpClient.PostAsync生产环境请求失败求助
.NET Framework中HttpClient.PostAsync连接被远程主机强制关闭问题排查
问题概述
在.NET Framework项目中调用HttpClient.PostAsync请求远程接口时,触发连接被远程主机强制关闭的异常。该功能在开发服务器(IIS部署)正常运行,但生产服务器上无法工作。已尝试修改ServicePointManager.SecurityProtocol添加TLS相关协议,问题仍未解决。
异常栈信息
System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult) at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult) --- End of inner exception stack trace --- at System.Net.TlsStream.EndWrite(IAsyncResult asyncResult) at System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar) --- End of inner exception stack trace --- at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context) at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar) --- End of inner exception stack trace --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at CanadianTireDashboard.Controllers.HomeController.<pickUpApi>d__109.MoveNext() in C:\Users\sbaqai\Documents\TFS\CanadianTireDashboard\CanadianTireDashboard\Controllers\HomeController.cs:line 865
核心调用代码
private async Task pickUpApi(string billOfLading) { ErrorFile f = new ErrorFile(); HomeController hc = new HomeController(); HttpResponseMessage pickUpRequestCall = null; //Send a request to url with an xml body try { var url = "https://www.tst-cfexpress.com/xml/pickup"; XmlSerializer xmlSerializer = new XmlSerializer(typeof(pickuprequest)); XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); pickuprequest cdn = new pickuprequest(); var values = cdn.getAll(billOfLading); try { var path = $@"C:\CDNTireJobs\Test\{billOfLading}.xml"; var encoding = Encoding.GetEncoding("ISO-8859-1"); using (XmlTextWriter tw = new XmlTextWriter(path, encoding)) { xmlSerializer.Serialize(tw, values, ns); tw.Close(); } } catch (FileNotFoundException e) { f.errorFile($"File Exception {e.Message}"); } var xmlcontent = System.IO.File.ReadAllText($@"C:\CDNTireJobs\Test\{billOfLading}.xml"); var content = new StringContent(xmlcontent, Encoding.GetEncoding("ISO-8859-1"), "application/xml"); ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12; ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true; pickUpRequestCall = await httpClient.PostAsync(url, content); f.errorFile(pickUpRequestCall.StatusCode.ToString()); if (pickUpRequestCall.StatusCode == HttpStatusCode.OK) { var strResBody = pickUpRequestCall.Content.ReadAsStringAsync().Result; f.errorFile(strResBody); } } catch(HttpRequestException e) { f.errorFile(e.ToString()); } }
排查方向与解决方案
1. 验证生产服务器的TLS协议支持
- 生产服务器可能存在系统层面的TLS协议限制,可通过PowerShell测试目标接口的兼容性:
Invoke-WebRequest -Uri "https://www.tst-cfexpress.com/xml/pickup" -UseBasicParsing - 检查注册表项
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols,确认TLS 1.2的Client端已启用(若目标接口支持,也可尝试启用TLS 1.3)。
2. 排查生产服务器网络环境
- 测试生产服务器与目标接口的连通性:
- 用浏览器直接访问目标URL,确认是否能正常加载
- 用telnet测试443端口:
telnet www.tst-cfexpress.com 443
- 确认生产服务器的防火墙/代理未拦截出站HTTPS请求,目标接口IP已加入出站白名单。
3. 修正HttpClient的使用方式
- 复用HttpClient实例:将
HttpClient声明为类的静态成员,避免每次请求创建新实例(频繁创建会耗尽连接池):private static readonly HttpClient httpClient = new HttpClient(); - 移除不必要的
HomeController实例创建,避免资源浪费。
4. 调整ServicePointManager设置时机
- 将
ServicePointManager.SecurityProtocol的配置移至应用启动时(如Global.asax的Application_Start方法),因为ServicePoint会被缓存,请求时再设置可能无法生效。
5. 修复证书验证逻辑
- 生产环境中不要全局禁用证书验证(
ServerCertificateValidationCallback返回true),这会带来安全风险。建议将目标接口的SSL证书导入生产服务器的受信任根证书颁发机构。
6. 优化请求内容生成逻辑
- 避免将XML写入本地文件再读取,直接在内存中序列化生成内容,减少文件IO权限或路径问题:
string xmlcontent; var encoding = Encoding.GetEncoding("ISO-8859-1"); using (var ms = new MemoryStream()) { xmlSerializer.Serialize(ms, values, ns); ms.Position = 0; using (var reader = new StreamReader(ms, encoding)) { xmlcontent = reader.ReadToEnd(); } } - 检查生产服务器上
C:\CDNTireJobs\Test路径的读写权限,确保XML文件能正常生成和读取。
内容的提问来源于stack exchange,提问作者Sameed Baqai
相关产品推荐
相关产品推荐

