ASP.NET Core 3.1调用OpenIBAN API随机出现SSL连接失败问题求助
问题代码
HttpClientHandler clientHandler = new HttpClientHandler(); clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; }; clientHandler.UseProxy = false; using (HttpClient client = new HttpClient(clientHandler)) { var reqUri = string.Format("{0}/{1}?getBIC=true&validateBankCode=true", AppSettings.Instance.ValidationSettings.IBANValidationUri, iban); Logger.Instance.LogInfo("IBAN Validation: Sending request"); using (HttpResponseMessage res = await client.GetAsync(reqUri)) { using (HttpContent content = res.Content) { if (content != null) { Logger.Instance.LogInfo("IBAN Validation: Reading data"); var data = res.Content.ReadAsStringAsync(); if (!string.IsNullOrEmpty(data.Result)) { result = JsonConvert.DeserializeObject<IBANValidationResult>(data.Result); } } } } }
问题背景
这段代码用于调用OpenIBAN API获取银行信息,部署在三台配置完全一致的IIS服务器上的ASP.NET Core 3.1 Web API中。出现以下间歇性异常:
- 三台服务器轮流出现调用超时,后端返回错误:
ERROR: The SSL connection could not be established, see inner exception
ERROR: Authentication failed because the remote party has closed the transport stream. - 异常不固定在某台服务器,时而某台正常,时而另一台异常。
可能原因及解决方案
1. HttpClient滥用导致套接字耗尽
当前代码每次调用都创建新的HttpClient并使用using销毁,这会导致TCP连接无法被复用,频繁创建/销毁会耗尽服务器的套接字资源,进而引发SSL握手失败(远程端关闭连接)。ASP.NET Core中推荐使用IHttpClientFactory来复用HttpClient实例和连接池。
修复方案:
- 在
Startup.cs中注册HttpClient:
services.AddHttpClient("OpenIBAN", client => { client.BaseAddress = new Uri(AppSettings.Instance.ValidationSettings.IBANValidationUri); }) .ConfigurePrimaryHttpMessageHandler(() => { var handler = new HttpClientHandler(); // 若OpenIBAN证书合法,建议移除该回调,恢复默认证书验证 handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true; handler.UseProxy = false; // 强制使用TLS 1.2+,避免版本协商问题 handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13; return handler; });
- 在业务服务中注入
IHttpClientFactory并复用HttpClient:
private readonly IHttpClientFactory _httpClientFactory; public YourIBANService(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public async Task<IBANValidationResult> ValidateIBANAsync(string iban) { IBANValidationResult result = null; var client = _httpClientFactory.CreateClient("OpenIBAN"); var reqUri = $"{iban}?getBIC=true&validateBankCode=true"; Logger.Instance.LogInfo("IBAN Validation: Sending request"); using (var res = await client.GetAsync(reqUri)) { res.EnsureSuccessStatusCode(); // 主动检查响应状态码 using (var content = res.Content) { if (content != null) { Logger.Instance.LogInfo("IBAN Validation: Reading data"); // 使用await替代.Result,避免线程阻塞和死锁风险 var data = await content.ReadAsStringAsync(); if (!string.IsNullOrEmpty(data)) { result = JsonConvert.DeserializeObject<IBANValidationResult>(data); } } } } return result; }
2. TLS版本协商异常
部分服务器可能默认未启用TLS 1.2/1.3,而OpenIBAN API可能不再支持旧版本TLS(如TLS 1.0/1.1),导致握手时远程端关闭连接。上述修复方案中已添加强制指定TLS版本的代码,可解决此类问题。
3. 网络层面间歇性拦截
- 检查服务器防火墙、负载均衡规则,是否存在间歇性的TCP连接重置或SSL流量拦截;
- 在异常服务器上直接用
curl或Invoke-WebRequest测试OpenIBAN API的连通性,观察是否有间歇性失败; - 排查DNS解析问题,确认服务器能稳定解析OpenIBAN API的域名。
4. 证书验证逻辑隐患
当前代码禁用了证书验证,虽然跳过了检查,但可能在某些SSL握手场景下引发异常。如果OpenIBAN的SSL证书是合法可信的,建议移除ServerCertificateCustomValidationCallback回调,恢复系统默认的证书验证逻辑,避免潜在的握手问题。
总结
优先修复HttpClient的使用方式(改用IHttpClientFactory),这是此类间歇性连接问题最常见的原因。同时修复异步等待的错误用法(用await替代.Result),再结合TLS版本配置和网络排查,基本可以解决问题。
内容的提问来源于stack exchange,提问作者Leon

