.NET HttpWebRequest(請求被中止: 未能創建 SSL/TLS 安全通道)和(基礎連接已經關閉: 發送時發生錯誤)問題查找解決


前言:

  前段時間在對接第三方接口的時候發生了一個非常奇葩的問題,就是使用 .NET Framework 4.6 HttpWebRequest進行網絡請求的相關問題。背景,關於調用第三方的接口都是使用使用自己封裝的一個HttpWebRequestHepler幫助類,在本地開發時調用第三方接口都是正常的。然而當我部署到運維給我一個服務器(阿里雲服務器)時剛開始提示是請求被中止: 未能創建 SSL/TLS 安全通道,之后經過一番修改以后就是提示基礎連接已經關閉: 發送時發生錯誤。之后嘗試了各種方法,還是沒有辦法解決基礎連接已經關閉: 發送時發生錯誤這個問題。最后真的是無能為力,光這個問題找了一下午的解決方案,最后換到了我自己的阿里雲服務器是可以正常調通第三方接口的。然后讓運維看了下服務器結果是這個服務器都沒有開通外網,所以導致了這個問題的出現。下面記錄下問題排除的過程,希望能夠幫助到遇到這種坑的小伙伴。

一、自己封裝的一個通用的HttpWebRequestHepler Http Web網絡請求幫助類:

    /// <summary>
    /// Http Web網絡請求幫助類
    /// </summary>
    public class HttpWebRequestHepler
    {
        private static HttpWebRequestHepler _httpWebRequestHepler;
        private string _resContent;//響應內容
        private string _errInfo;//錯誤信息
        private int _responseCode;//響應狀態碼

        public static HttpWebRequestHepler _
        {
            get => _httpWebRequestHepler ?? (_httpWebRequestHepler = new HttpWebRequestHepler());
            set => _httpWebRequestHepler = value;
        }

        /// <summary>
        /// 數據請求
        /// </summary>
        /// <param name="requestUrl">請求地址</param>
        /// <param name="postData">請求參數</param>
        /// <param name="accessToken">授權token</param>
        /// <param name="contentType">請求標頭值類型</param>
        /// <param name="method">請求方式</param>
        /// <returns></returns>
        public string HttpWebResponseData(string requestUrl, string postData, string accessToken = "", string contentType = "application/json", string method = "POST")
        {
            HttpWebResponse wr = null;

            try
            {
                var hp = (HttpWebRequest)WebRequest.Create(requestUrl);
                hp.Timeout = 60 * 1000 * 10;//以毫秒為單位,設置等待超時10分鍾
                hp.Method = method;
                hp.ContentType = contentType;
                if (!string.IsNullOrWhiteSpace(accessToken))
                {
                    hp.Headers.Add("Authorization", "Bearer " + accessToken);//增加headers請求頭信息
                }


                if (postData != "")//帶參數請求
                {
                    byte[] data = Encoding.UTF8.GetBytes(postData);
                    hp.ContentLength = data.Length;
                    Stream ws = hp.GetRequestStream();

                    // 發送數據
                    ws.Write(data, 0, data.Length);
                    ws.Close();
                }

                wr = (HttpWebResponse)hp.GetResponse();
                var sr = new StreamReader(wr.GetResponseStream() ?? throw new InvalidOperationException(), Encoding.UTF8);

                this._resContent = sr.ReadToEnd();
                sr.Close();
                wr.Close();
            }
            catch (Exception exp)
            {
                this._errInfo += exp.Message;
                if (wr != null)
                {
                    this._responseCode = Convert.ToInt32(wr.StatusCode);
                }

                return this._resContent;
            }

            this._responseCode = Convert.ToInt32(wr.StatusCode);

            return this._resContent;
        }

    }

二、請求被中止: 未能創建 SSL/TLS 安全通道問題解決:

  把項目部署到阿里雲服務器中,請求第三方提示請求被中止: 未能創建 SSL/TLS 安全通道。首先字面上可以看出來這個https請求安全協議的問題。微軟官方說明是,NET 4.6需要添加

ServicePointManager.SecurityProtocol屬性,指定schnanel安全包支持的安全協議

微軟官方解釋:

此屬性選擇要用於新連接的安全套接字層 (SSL) 或傳輸層安全性 (TLS) 協議的版本;不會更改現有連接。

從 .NET Framework 4.7 開始,此屬性的默認值為 SecurityProtocolType.SystemDefault 。 這允許基於 SslStream ((如 FTP、HTTP 和 SMTP) )的 .NET Framework 網絡 api 從操作系統或系統管理員執行的任何自定義配置繼承默認安全協議。 有關默認情況下在每個版本的 Windows 操作系統上啟用了哪些 SSL/TLS 協議的信息,請參閱 TLS/SSL (SCHANNEL SSP) 中的協議 

對於通過 .NET Framework 4.6.2 的 .NET Framework 版本,不會列出此屬性的默認值。 安全環境不斷變化,默認的協議和保護級別會隨着時間的推移而更改,以避免已知的漏洞。 默認值因單獨的計算機配置、已安裝的軟件和應用的修補程序而異。

 解決方案:

//todo:指定請求包的安全協議,因為不知道你當前項目到底是哪個版本所以為了安全保障都加上
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.SystemDefault | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;

三、基礎連接已經關閉: 發送時發生錯誤

        這個問題查閱了網上幾個比較典型的博客試了下,結果都沒有辦法解決我的問題,一下記錄下這幾個博客的解決方案,希望可以幫助到遇到這樣問題的小伙伴。

1、一般來說添加了上面的ServicePointManager.SecurityProtocol屬性就可以解決這個基礎連接關閉的問題。

2、C# HttpRequest基礎連接已經關閉: 接收時發生意外錯誤(原文地址):

//增加下面兩個屬性即可
hp.KeepAlive = false;
hp.ProtocolVersion = HttpVersion.Version10;

四、開啟阿里雲服務器外網(我的解決方案)

  查看一下你的服務器是否開通了外網,假如沒有開通服務器外網在進行嘗試。阿里雲服務器配置外網訪問參考。因為這個奇葩問題花費了一天寶貴的時間,考慮問題還是得多方面考慮。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM