使用 HttpClient &用于 HTTPS TLS1.2 的 HttpWebRequest

使用 HttpClient &用于 HTTPS TLS1.2 的 HttpWebRequest

问题描述:

在控制台应用程序中,尝试访问配置了 TLS 1.2 的https"端点.

In Console Application, while trying to hit the "https" Endpoint configured with TLS 1.2.

在 C# 中在使用 HttpClient 时,我收到了来自端点的成功响应

In C# While using HttpClient I am getting the success response from endpoint

       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时

But when using 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 时我做错了什么?

Please guide me what I am doing wrong while using HttpWebRequest?

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

You need to set the SecurityProtocol property before calling WebRequest.Create method.

更新:

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

Let me add some details that explain why this should be correct.

referencesource.microsoft.com.

Having a look at the source code of WebRequest.Create(string) method from referencesource.microsoft.com.

返回值为:

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

现在,让我们看看 Create(Uri, bool) 方法,它从 WebRequestPrefixElement.Creator.Create(Uri) 返回一些对象.

so now, Let's take a look at Create(Uri, bool) method, it returns some object from WebRequestPrefixElement.Creator.Create(Uri).

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

Creator is a property inside of WebRequestPrefixElement and it's of type IWebRequestCreate. In your case, IWebRequestCreate will be an HttpRequestCreator object.

HttpRequestCreator.Create方法的代码:

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

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

Finally, Let's look at that HttpWebRequest constructor. You'll see a long code there, but really what is important is this line:

SslProtocols = (SslProtocols)ServicePointManager.SecurityProtocol;

所以 SecurityProtocol 值被分配给名为 SslProtocols 的属性.因此,现在很明显,当您调用 Create 方法时,使用了 SecurityProtocol 并保存到 HttpWebRequest 对象,因此更改 SecurityProtocol 调用 Create 后不会改变 HttpWebRequest 对象使用的协议.

so the SecurityProtocol value is assigned to a property called SslProtocols. So, it's obvious now that SecurityProtocol is used and kind of saved to the HttpWebRequest object when you call Create method, so changing SecurityProtocol after calling Create will not change the protocol used by the HttpWebRequest object.