使用 HttpClient 进行 Https 调用

我一直在使用 HttpClient来使用 C # 进行 WebApi 调用。与 WebClient相比,看起来简洁快捷。然而,我在打 Https电话的时候被堵住了。

我怎样才能使下面的代码使 Https调用?

HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://foobar.com/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/xml"));


var task = httpClient.PostAsXmlAsync<DeviceRequest>(
"api/SaveData", request);

编辑1: 上面的代码可以很好地进行 http 调用。但是,当我将该方案更改为 https 时,它就不起作用了。以下是得到的错误:

基础连接已关闭: 无法建立信任 SSL/TLS 安全信道的关系。

编辑2: 将方案更改为 https 是第一步。

如何提供证书和公钥/私钥以及 C # 请求。

373657 次浏览

只需在 URI 中指定 HTTPS。

new Uri("https://foobar.com/");

Foobar.com 将需要一个可信的 SSL 证书,否则您的调用将因不可信错误而失败。

编辑答案: 使用 HttpClient 的客户端证书

WebRequestHandler handler = new WebRequestHandler();
X509Certificate2 certificate = GetMyX509Certificate();
handler.ClientCertificates.Add(certificate);
HttpClient client = new HttpClient(handler);

编辑答案2: 如果您正在连接的服务器已禁用 SSL、 TLS 1.0和1.1,而您仍在运行。NET 框架4.5(或更低版本)你需要做出选择

  1. 升级至.Net 4.6 + (默认情况下支持 TLS 1.2)
  2. 添加注册表更改以指示4.5通过 TLS1.2进行连接(参见: 销售小组报告获取 compat 和更改 OR 校验键 IISCrypto参见 Ronald Ramos 回答评论)
  3. 添加应用程序代码来手动配置. NET 以通过 TLS1.2进行连接(参见 Ronald Ramos 回答)

您的代码应该按以下方式进行修改:

httpClient.BaseAddress = new Uri("https://foobar.com/");

您只需使用 https: URI 方案。 在 MSDN 上有一个关于安全 HTTP 连接的有用的 给你页面:

使用 https: URI 方案

HTTP 协议定义了两个 URI 方案:

Http: 用于未加密的连接。

Https: 用于应该加密的安全连接。此选项还使用数字证书和证书颁发机构来验证服务器是否是它声称的那个服务器。

此外,考虑到 HTTPS 连接使用 SSL 证书。请确保您的安全连接具有此证书,否则请求将失败。

编辑:

以上代码可以很好地进行 http 调用 它不工作,让我张贴的错误。

什么意思? 请求失败? 抛出异常? 澄清你的问题。

如果请求失败,那么问题应该是 SSL 证书。

要解决这个问题,可以使用类 HttpWebRequest,然后使用它的属性 ClientCertificate。 此外,您可以找到关于如何使用证书发出 HTTPS 请求的有用示例 给你

下面是一个例子(如前面链接的 MSDN 页面所示) :

//You must change the path to point to your .cer file location.
X509Certificate Cert = X509Certificate.CreateFromCertFile("C:\\mycert.cer");
// Handle any certificate errors on the certificate from the server.
ServicePointManager.CertificatePolicy = new CertPolicy();
// You must change the URL to point to your Web server.
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://YourServer/sample.asp");
Request.ClientCertificates.Add(Cert);
Request.UserAgent = "Client Cert Sample";
Request.Method = "GET";
HttpWebResponse Response = (HttpWebResponse)Request.GetResponse();

只要在 URI 中指定 HTTPS 就可以了。

httpClient.BaseAddress = new Uri("https://foobar.com/");

如果请求与 HTTP 一起工作,但与 HTTPS 一起失败,那么 这肯定是一个证书问题。确保调用方信任证书颁发方,并且证书没有过期。一个快速而简单的检查方法是尝试在浏览器中进行查询。

您还可能希望检查服务器(如果是您的服务器和/或如果可以的话)是否设置为正确地服务 HTTPS 请求。

我在连接到 GitHub 时遇到了同样的问题,这需要一个用户代理。因此,提供这一点就足够了,而不需要生成证书

var client = new HttpClient();


client.BaseAddress = new Uri("https://api.github.com");
client.DefaultRequestHeaders.Add(
"Authorization",
"token 123456789307d8c1d138ddb0848ede028ed30567");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add(
"User-Agent",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");

如果服务器只支持更高的 TLS 版本,比如仅支持 TLS 1.2,那么它仍然会失败,除非您的客户端 PC 配置为默认使用更高的 TLS 版本。要解决此问题,请在代码中添加以下内容:

System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

修改您的代码示例时,它将是

HttpClient httpClient = new HttpClient();


//specify to use TLS 1.2 as default connection
System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;


httpClient.BaseAddress = new Uri("https://foobar.com/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
    

var task = httpClient.PostAsXmlAsync<DeviceRequest>("api/SaveData", request);

您可以尝试使用 客户端 Nuget 软件包: 下载该软件包后,您可以这样实现它:

 var handler = new ModernHttpClient.NativeMessageHandler()
{
UseProxy = true,
};




handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
handler.PreAuthenticate = true;
HttpClient client = new HttpClient(handler);

当连接到 https时,我也得到了这个错误,我在 HttpClient httpClient = new HttpClient();之前添加了这一行,并成功连接:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

我是从 这个答案另一个相似的答案知道的,评论中提到:

这是一个在开发中非常有用的技巧,因此在它周围放置一个 # if DEBUG # endf 语句是您至少应该做的,以使它更安全,并阻止它最终进入生产环境

此外,我没有尝试在 另一个答案中使用 new X509Certificate()new X509Certificate2()来制作证书的方法,我不确定简单地由 new()创建是否可行。

编辑: 一些参考文献:

在 IIS7中创建自签名服务器证书

在 IIS7中导入和导出 SSL 证书

将.pfx 转换为

使用 Server證 icateValidationCallback 的最佳实践

我发现拇指指纹的值等于 x509certificate.GetCertHashString():

检索证书的拇指指纹

对于错误:

基础连接已关闭: 无法建立信任 SSL/TLS 安全信道的关系。

我认为您需要使用以下代码无条件地接受证书

ServicePointManager.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => true;

正如 反对派在回答问题 连接到 sslWebAPI 的.NET 客户端时所写的。

我还发现了一个错误:

基础连接已关闭: 无法建立信任 SSL/TLS 安全信道的关系。

... 使用一个以 Xamarin 表单 Android为目标的应用程序,该应用程序试图从需要 TLS 1.3.的 API 提供程序请求资源

解决方案是更新项目配置以替换 Xamarin“托管”(。NET) http 客户端(Xamarin Forms v2.5不支持 TLS 1.3) ,而是使用 android 本机客户端。

这是一个简单的项目切换在视觉工作室。见下面的截图。

  • 工程项目物业
  • Android 选项
  • 高级
  • 列表项目
  • 将“ HttpClient 实现”更改为“ Android”
  • 将 SSL/TLS 实现更改为“ NativeTLS 1.2 +”

enter image description here

将以下声明添加到类中:

public const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
public const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;

之后:

var client = new HttpClient();

还有:

ServicePointManager.SecurityProtocol = Tls12;
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 /*| SecurityProtocolType.Tls */| Tls12;

高兴了? :)

我遇到了这个问题,在我的情况下,解决方案非常简单: 使用管理员权限打开 VisualStudio。我尝试了以上所有的解决方案,直到我这样做才起作用。希望能为某人节省宝贵的时间。

HttpClientHandler级别有一个非全球性的环境:

var handler = new HttpClientHandler()
{
SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls
};


var client = new HttpClient(handler);

因此可以启用最新的 TLS 版本。

注意,默认值 SslProtocols.Default实际上是 SslProtocols.Ssl3 | SslProtocols.Tls(检查.Net Core 2.1和.Net Framework 4.7.1)。

更新: 在.Net 5.0中,HttpClientHandler.SslProtocols的默认值是 None,这意味着以下内容(参见 医生) :

允许操作系统选择要使用的最佳协议,并阻塞不安全的协议。除非你的应用程序有特定的理由不这样做,否则你应该使用这个字段。

我同意 felickz 的观点,但是我也想添加一个例子来说明 c # 中的用法。我在 Windows 服务中使用 SSL,如下所示。

    var certificatePath = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "bin");
gateway = new GatewayService();
gateway.PreAuthenticate = true;




X509Certificate2 cert = new X509Certificate2(certificatePath + @"\Attached\my_certificate.pfx","certificate_password");
gateway.ClientCertificates.Add(cert);


ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
gateway.UserAgent = Guid.NewGuid().ToString();
gateway.Timeout = int.MaxValue;

如果我要在 Web 应用程序中使用它,我只需要像下面这样改变代理端的实现:

public partial class GatewayService : System.Web.Services.Protocols.SoapHttpClientProtocol // to => Microsoft.Web.Services2.WebServicesClientProtocol

下面是在 HTTPS 调用中工作的代码

UriBuilder builder = new UriBuilder("https://yourdomain.com/");
builder.Query = "id=10";
//Create a query
HttpClient client = new HttpClient();
System.Net.ServicePointManager.SecurityProtocol =
SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
client.DefaultRequestHeaders.Add("Authorization", userprofile.Token);
var result = client.GetAsync(builder.Uri).Result;
using (StreamReader sr = new
StreamReader(result.Content.ReadAsStreamAsync().Result))
{
responseres = sr.ReadToEnd();
}