使用HttpClient进行Https调用

Abh*_*eet 146 c# asp.net-web-api

我一直在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);
Run Code Online (Sandbox Code Playgroud)

编辑1: 上面的代码适用于进行http调用.但是,当我将方案更改为https时,它不起作用.这是获得的错误:

底层连接已关闭:无法为SSL/TLS安全通道建立信任关系.

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

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

Ron*_*mos 189

如果服务器仅支持更高的TLS版本(如TLS 1.2),则它仍将失败,除非您的客户端PC默认配置为使用更高的TLS版本.要解决此问题,请在代码中添加以下内容.

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Run Code Online (Sandbox Code Playgroud)

修改你的示例代码,就是这样

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);
Run Code Online (Sandbox Code Playgroud)

  • 您不必使用 .Net 4.5 或更高版本,但这会更容易。您还可以找到 Tls1.2 的枚举值,然后进行显式转换,假设它是 3,然后在 &lt; .Net 4.5 中您可以执行 *.SecurityProtocol = (SecurityProtocolType)3; 它会起作用的。.net 4.5+ 仍然在 4.0 运行时上运行,只是您正在使用的库的版本没有定义该枚举值,但它仍然存在于框架中。 (3认同)

fel*_*ckz 123

只需在URI中指定HTTPS即可.

new Uri("https://foobar.com/");
Run Code Online (Sandbox Code Playgroud)

Foobar.com需要拥有受信任的SSL证书,否则您的呼叫将因不受信任的错误而失败.

编辑答案:使用HttpClient的ClientCertificates

WebRequestHandler handler = new WebRequestHandler();
X509Certificate2 certificate = GetMyX509Certificate();
handler.ClientCertificates.Add(certificate);
HttpClient client = new HttpClient(handler);
Run Code Online (Sandbox Code Playgroud)

编辑答案2:如果您连接的服务器已禁用SSL,TLS 1.0和1.1,并且您仍在运行.NET framework 4.5(或更低版本),则需要做出选择

  1. 升级到.Net 4.6+(默认支持TLS 1.2)
  2. 添加注册表更改以指示4.5通过TLS1.2连接(请参阅:salesforce writeup for compat和keys更改或签出IISCrypto查看Ronald Ramos 回答评论)
  3. 添加应用程序代码以手动配置.NET以通过TLS1.2连接(请参阅Ronald Ramos 答案)

  • @developer让我们只希望代码不会进入你的生产版本:) (6认同)
  • 在开发或处理自签名证书时,您可以使用以下命令忽略不受信任的证书错误:`ServicePointManager.ServerCertificateValidationCallback + =(sender,cert,chain,sslPolicyErrors)=> true;` (5认同)
  • 什么是`GetMyX509Certificate`? (5认同)

Alb*_*ano 13

您的代码应该以这种方式修改:

httpClient.BaseAddress = new Uri("https://foobar.com/");
Run Code Online (Sandbox Code Playgroud)

您只需使用https:URI方案即可.有一个有用的页面在这里 MSDN上有关安全的HTTP连接.确实:

使用https:URI方案

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

http:用于未加密的连接.

https:用于应加密的安全连接.此选项还使用数字证书和证书颁发机构来验证服务器是否是其声称的身份.

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

编辑:

上面的代码适用于进行http调用.但是,当我将方案更改为https时,它不起作用,让我发布错误.

这是什么意思不起作用?请求失败了吗?抛出异常?澄清你的问题.

如果请求失败,则问题应该是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();
Run Code Online (Sandbox Code Playgroud)


sto*_*ran 9

在以下级别有一个非全局设置HttpClientHandler

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

var client = new HttpClient(handler);
Run Code Online (Sandbox Code Playgroud)

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

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

  • 在 .NET Framework 的早期版本中,此属性是私有的 (2认同)

yu *_*ian 7

连接时https也收到此错误,我在此行之前添加HttpClient httpClient = new HttpClient();并成功连接:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
Run Code Online (Sandbox Code Playgroud)

我从“ 这个答案”和“ 另一个类似的答案”知道这一点,并且评论中提到:

这在开发中非常有用,因此在其中添加#if DEBUG #endif语句至少是使该代码更安全并停止在生产中使用的最少方法。

此外,我没有尝试使用“ 其他答案”中使用new X509Certificate()new X509Certificate2()制作证书的方法,我不确定简单地创建by new()是否行得通。

编辑: 一些参考:

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

在IIS 7中导入和导出SSL证书

将.pfx转换为.cer

使用ServerCertificateValidationCallback的最佳做法

我发现Thumbprint的值等于x509certificate.GetCertHashString()

检索证书的指纹


Car*_*ngo 6

连接到需要用户代理的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");
Run Code Online (Sandbox Code Playgroud)

  • 你真的认为我的令牌以`123456789`开头吗? (16认同)
  • 你应该撤销你与互联网共享的令牌,我认为GitHub可能会自动完成. (2认同)