C# HttpClient配置pem/key证书及信任CA实现大文件上传至REST API
问题根因
你当前的代码存在3个核心问题,和Perl、Python的实现逻辑不匹配:
- 客户端证书加载不完整:仅加载了
TECHUSER.pem公钥文件,没有关联对应的TECHUSER.key私钥文件,双向TLS认证时服务端无法验证你的客户端身份 - 缺失自定义服务端CA信任配置:服务端用的是私有CA颁发的证书,C#默认不会信任不在系统根证书存储中的私有CA,需要自定义校验逻辑
- 大文件上传逻辑存在性能缺陷:将1GB文件全部读入
MemoryStream会占用大量内存,大概率会触发内存溢出
修复方案
以下代码适配.NET 5+版本,如果使用.NET Framework可以看最后适配说明:
using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Globalization; // 1. 同时加载客户端证书公钥和私钥 X509Certificate2 clientCert = X509Certificate2.CreateFromPemFile(@"TECHUSER.pem", @"TECHUSER.key"); // Windows环境如果报私钥不可用错误,加下面这行转成临时PFX格式 // clientCert = new X509Certificate2(clientCert.Export(X509ContentType.Pfx)); // 2. 加载服务端信任的CA证书 X509Certificate2 trustedCA = new X509Certificate2(@"Server_TrustedCA.pem"); var httpClientHandler = new HttpClientHandler(); httpClientHandler.ClientCertificates.Clear(); httpClientHandler.ClientCertificates.Add(clientCert); httpClientHandler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12; httpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual; // 3. 自定义服务端证书验证逻辑,信任指定的私有CA httpClientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { if (sslPolicyErrors == SslPolicyErrors.None) return true; chain.ChainPolicy.ExtraStore.Add(trustedCA); chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; return chain.Build(cert as X509Certificate2); }; // 注意:HttpClient建议全局复用一个实例,不要每次请求都新建,这里仅做示例 using (HttpClient httpClient = new HttpClient(httpClientHandler)) // 大文件直接用FileStream读取,不要加载到内存 using (var fileStream = new FileStream(@"OneGbFile.txt", FileMode.Open, FileAccess.Read)) using (var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture))) { content.Add(new StreamContent(fileStream), "file", "OneGbFile.txt"); // 配置和Python一致的超时时间 httpClient.Timeout = TimeSpan.FromSeconds(54000); // 生产环境建议用await异步调用,不要用.Result阻塞避免死锁 HttpResponseMessage result = await httpClient.PostAsync("https://myserver.url", content); string responseStr = await result.Content.ReadAsStringAsync(); }
.NET Framework适配说明
低版本.NET Framework不支持CreateFromPemFile方法,可以先通过openssl命令将证书和私钥合并为PFX格式:openssl pkcs12 -export -in TECHUSER.pem -inkey TECHUSER.key -out TECHUSER.pfx
生成PFX时设置密码后,直接加载PFX即可:X509Certificate2 clientCert = new X509Certificate2(@"TECHUSER.pfx", "你设置的PFX密码");
内容的提问来源于stack exchange,提问作者Josue Medrano
相关产品推荐
相关产品推荐

