使用HttpClient进行Https调用

我一直在使用HttpClient使用C#进行WebApi调用。 与WebClient相比,似乎整洁快捷。 不过,当我打开Https调用时,

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

 HttpClient httpClient = new HttpClient(); httpClient.BaseAddress = new Uri("http://foobar.com/"); httpClient.DefaultRequestHeaders.Accept.Clear(); httpClient.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/xml")); var task = httpClient.PostAsXmlAsync<DeviceRequest>( "api/SaveData", request); 

编辑1:上面的代码工作正常进行http调用。 但是,当我改变scheme到https它不起作用。 这是得到的错误:

底层连接已closures:无法build立SSL / TLS安全通道的信任关系。

编辑2:改变scheme为https是:第一步。

如何随C#请求一起提供证书和公钥/私钥。

只需在URI中指定HTTPS即可。

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

Foobar.com将需要有一个可信的SSL证书或您的电话将失败,不可信的错误。

编辑答案: 与HttpClient ClientCertificates

 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(或以下),您需要作出select

  1. 升级到.Net 4.6+( 默认支持TLS 1.2 )
  2. 添加registry更改以指示4.5通过TLS1.2进行连接(请参阅:用于compat的salesforce writeup和要更改的键或检出IISCrypto请参阅Ronald Ramos answer comments )
  3. 添加应用程序代码以手动configuration.NET以通过TLS1.2进行连接(请参阅Ronald Ramos的答案 )

如果服务器仅支持TLS 1.2等更高版本的TLS版本,则除非您的客户端PC默认configuration为使用更高的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); 

你的代码应该这样修改:

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

您只需使用https: URIscheme。 在MSDN上有一个关于安全HTTP连接的有用的页面。 确实:

使用https:URIscheme

HTTP协议定义了两个URIscheme:

http:用于未encryption的连接。

https:用于应该encryption的安全连接。 此选项也使用数字证书和证书颁发机构来validation服务器是谁声称。

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

编辑:

上面的代码可以很好地进行http调用。 但是当我改变scheme到https不起作用,让我发布错误。

这是什么意思不起作用? 请求失败? 抛出exception? 澄清你的问题。

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

要解决这个问题,你可以使用HttpWebRequest类,然后使用它的属性ClientCertificate 。 此外,您可以在这里find有关如何使用证书进行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(); 

当连接到需要用户代理的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"); 

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

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

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

您也可能需要检查服务器(如果是您的和/或可以的话)是否设置为正确提供HTTPS请求。

你可以尝试使用ModernHttpClient的 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 #endif声明是最不重要的,你应该做的更安全,并停止在生产结束

此外,我没有尝试这种方法, 另一个答案使用new X509Certificate()new X509Certificate2()来作出一个证书,我不确定简单地创buildnew()将工作与否。