首页 > 解决方案 > 使用 HttpClient 和 HttpWebRequest 进行 Https TLS1.2

问题描述

在控制台应用程序中,尝试访问使用 TLS 1.2 配置的“https”端点。

在 C# 中使用 HttpClient 时,我从端点获得成功响应

       HttpClient httpClient = new HttpClient();

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

        httpClient.BaseAddress = new Uri("HTTPSENDPOINT");
        httpClient.DefaultRequestHeaders.Accept.Clear();
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        var content = new StringContent("POSTDATA");
        var task = httpClient.PostAsync("/Token", content);

        task.Wait();

        Console.WriteLine(task.Result.Content.ReadAsStringAsync().Result.ToString());

但是当使用 HttpWebRequest

       var request = (HttpWebRequest)WebRequest.Create("HTTPSENDPOINT/Token");
       var postData = "POSTDATA";
        var data = Encoding.ASCII.GetBytes(postData);

        System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = data.Length;

        using (var stream = request.GetRequestStream()) // Getting Error in GetRequestStream() method call
        {
            stream.Write(data, 0, data.Length);
        }

        var response = (HttpWebResponse)request.GetResponse();

        var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

我得到以下错误

The request was aborted: Could not create SSL/TLS secure channel.

请指导我在使用 HttpWebRequest 时做错了什么?

标签: c#tls1.2

解决方案


您需要在调用方法之前SecurityProtocol设置属性。WebRequest.Create

更新:

让我添加一些细节来解释为什么这应该是正确的。

查看来自referencesource.microsoft.comWebRequest.Create(string)的方法的源代码。

返回值为:

return Create(new Uri(requestUriString), false);

所以现在,让我们看一下Create(Uri, bool)方法,它从WebRequestPrefixElement.Creator.Create(Uri).

Creator是内部的一个属性WebRequestPrefixElement,它的类型是IWebRequestCreate. 在您的情况下,IWebRequestCreate将是一个HttpRequestCreator对象。

查看HttpRequestCreator.Create方法的代码:

public WebRequest Create( Uri Uri ) {
    //
    // Note, DNS permissions check will not happen on WebRequest
    //
    return new HttpWebRequest(Uri, null);
}

最后,让我们看看那个HttpWebRequest构造函数。你会在那里看到很长的代码,但真正重要的是这一行:

SslProtocols = (SslProtocols)ServicePointManager.SecurityProtocol;

因此该SecurityProtocol值被分配给一个名为SslProtocols. 所以,现在很明显,调用方法SecurityProtocol时使用并保存到 HttpWebRequest 对象中,因此调用更改不会更改 HttpWebRequest 对象使用的协议。CreateSecurityProtocol Create


推荐阅读