C#實現HTTP訪問類HttpHelper

来源:https://www.cnblogs.com/huaxiaorui/archive/2022/09/05/16658624.html
-Advertisement-
Play Games

一:背景 前段時間在訓練營上課的時候就有朋友提到一個問題,為什麼 Windbg 附加到 C# 程式後,程式就處於中斷狀態了?它到底是如何實現的? 其實簡而言之就是線程的遠程註入,這一篇就展開說一下。 二:實現原理 1. 基本思路 WinDbg 在附加進程的時候,會註入一個線程到 C# 進程 中,註入 ...


在項目開發過程中,我們經常會訪問第三方介面,如我們需要接入的第三方介面是Web API,這時候我們就需要使用HttpHelper調用遠程介面了。示例中的HttpHelper類使用Log4Net記錄了每次調用的請求內容和響應內容的日誌,並且每條日誌都帶上了鏈路ID和標識,這樣方便我們在排查問題時能快速的找到當時的請求和響應內容,進而定位分析問題。大家在使用的時候如不需要記錄日誌,刪除掉即可。

HttpHelper類代碼如下:

    public class HttpHelper : IDisposable
    {
        private bool _disposable = false;
        /// <summary>
        /// 請求編碼格式預設utf-8;
        /// </summary>
        public Encoding HtmlEncoding = Encoding.UTF8;
        /// <summary>
        /// 請求時間
        /// </summary>
        public int Timeout = 5000;

        public CookieContainer Cookies = null;
        /// <summary>
        /// 是否記錄Cookies
        /// </summary>
        public bool IsRecordCookie = false;

        public string ContentType = "application/x-www-form-urlencoded";

        public string AcceptLanguage = "en-US, en; q=0.8, zh-Hans-CN; q=0.5, zh-Hans; q=0.3";

        public string KeepAlive = "Keep-Alive";

        public string Accept = "*/*";

        private const string UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240";

        private static ILogger Logger = Log4NetLoggerFactory.Instance.Create("remote.info");

        public HttpHelper()
        {
            //允許最大連接數,突破Http協議的併發連接數限制
            ServicePointManager.DefaultConnectionLimit = 512;
        }

        /// <summary>
        /// 上傳圖片
        /// </summary>
        /// <param name="url"></param>
        /// <param name="bArr"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public HttpRequestEntity RequestFile(string url, byte[] bArr, string fileName = "")
        {
            var result = new HttpRequestEntity { IsSuccess = 0 };
            //後續需要再放開,啟用時需增加日誌收集
            //if (string.IsNullOrEmpty(url))
            //    throw new ArgumentNullException("請求Url不能為空值");

            //if (bArr == null || bArr.Length <= 0)
            //    throw new AccessViolationException("缺少輸入數據");

            //Stream requestStream = null;
            //StreamReader streamReader = null;
            //HttpWebResponse response = null;
            //HttpWebRequest request = null;
            //try
            //{
            //    request = WebRequest.Create(url) as HttpWebRequest;
            //    request.AllowAutoRedirect = true;
            //    request.Method = "POST";
            //    string boundary = DateTime.Now.Ticks.ToString("X"); // 隨機分隔線
            //    request.ContentType = "multipart/form-data;charset=utf-8;boundary=" + boundary;
            //    byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
            //    byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");

            //    if (string.IsNullOrEmpty(fileName))
            //        fileName = DateTime.Now.ToString("yyyyMMddHHmmss");

            //    //請求頭部信息 
            //    StringBuilder sbHeader = new StringBuilder(string.Format("Content-Disposition:form-data;name=\"file\";filename=\"{0}\"\r\nContent-Type:application/octet-stream\r\n\r\n", fileName));
            //    byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());
            //    request.Headers.Add("auth", fileName);
            //    Stream postStream = request.GetRequestStream();
            //    postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
            //    postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
            //    postStream.Write(bArr, 0, bArr.Length);
            //    postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
            //    postStream.Close();
            //    response = request.GetResponse() as HttpWebResponse;
            //    requestStream = response.GetResponseStream();
            //    if (response.StatusCode == HttpStatusCode.OK)
            //    {
            //        result.IsSuccess = 0;
            //        if (requestStream != null)
            //        {
            //            streamReader = new StreamReader(requestStream, HtmlEncoding);
            //            result.ResponseContent = streamReader.ReadToEnd();
            //        }
            //    }
            //}
            //catch (Exception ex)
            //{
            //    result.IsSuccess = 1;
            //    result.ResponseContent = ex.Message;
            //}
            //finally
            //{
            //    if (requestStream != null)
            //    {
            //        requestStream.Close();
            //        requestStream.Dispose();
            //    }

            //    if (streamReader != null)
            //    {
            //        streamReader.Close();
            //        streamReader.Dispose();
            //    }

            //    request.Abort();
            //    if (response != null)
            //        response.Close();

            //}

            return result;
        }

        /// <summary>
        /// 基本請求方法
        /// </summary>
        /// <param name="requestType">HTTP請求類型</param>
        /// <param name="url">請求的URL</param>
        /// <param name="requestData">請求參數</param>
		/// <param name="traceID">鏈路ID,方便查詢日誌</param>
		/// <param name="markType">請求標識,方便查詢日誌</param>
        /// <returns></returns>
        private HttpRequestEntity BaseRequest(RequestType requestType, string url, string requestData, string traceID,string markType)
        {
            var result = new HttpRequestEntity { IsSuccess = 0 };

            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException("請求Url不能為空值");

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            Dictionary<string, object> resultLog = new Dictionary<string, object>();//log對象
            resultLog.Add("logType", "remote");
            resultLog.Add("traceID", traceID);
            resultLog.Add("localIp", IpHelper.LocalIp);
            resultLog.Add("markType", markType);
            resultLog.Add("url", url);            
            resultLog.Add("requestContent", HttpUtility.UrlDecode(requestData, Encoding.UTF8));
            resultLog.Add("createTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
            StackTrace ss = new StackTrace(true);
            System.Reflection.MethodBase mb = ss.GetFrame(2).GetMethod();//0表示當前棧空間,1表示上一級的棧空間,依次類推
            resultLog.Add("className", mb.DeclaringType.FullName);
            resultLog.Add("methodName", mb.Name);
            HttpStatusCode statusCode = HttpStatusCode.OK;

            if (IsRecordCookie)
                Cookies = new CookieContainer();
            Stream requestStream = null;
            StreamReader streamReader = null;

            HttpWebRequest webRe = null;
            HttpWebResponse webPos = null;
            try
            {
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                    webRe = WebRequest.Create(url) as HttpWebRequest;
                    webRe.ProtocolVersion = HttpVersion.Version10;
                }
                else
                {
                    webRe = (HttpWebRequest)WebRequest.Create(url);
                }

                webRe.Headers.Add("Accept-Language", AcceptLanguage);
                webRe.Headers.Add("Keep-Alive", KeepAlive);
                webRe.UserAgent = UserAgent;
                webRe.Accept = Accept;
                webRe.Timeout = Timeout;
                webRe.ReadWriteTimeout = Timeout;
                webRe.CookieContainer = Cookies;

                if (requestType == RequestType.Post)
                {
                    webRe.ContentType = string.Format("{0}; {1}", ContentType, HtmlEncoding.BodyName);
                    byte[] datas = HtmlEncoding.GetBytes(requestData);
                    webRe.Method = "POST";
                    webRe.ContentLength = datas.Length;
                    webRe.MaximumResponseHeadersLength = -1;
                    requestStream = webRe.GetRequestStream();
                    requestStream.Write(datas, 0, datas.Length);
                    requestStream.Flush();
                    requestStream.Close();
                }
                else
                    webRe.Method = "GET";

                webPos = (HttpWebResponse)webRe.GetResponse();
                resultLog.Add("requestType", webRe.Method);
                statusCode = webPos.StatusCode;
                result.ResponseLength = webPos.ContentLength;
                result.ResponseEncodingName = webPos.ContentEncoding;

                requestStream = webPos.GetResponseStream();
                if (webPos.StatusCode == HttpStatusCode.OK)
                {
                    result.IsSuccess = 0;

                    if (requestStream != null)
                    {
                        streamReader = new StreamReader(requestStream, HtmlEncoding);
                        result.ResponseContent = streamReader.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {
                result.IsSuccess = 1;
                result.ResponseContent = ex.Message;
            }
            finally
            {
                if (requestStream != null)
                {
                    requestStream.Close();
                    requestStream.Dispose();
                }

                if (streamReader != null)
                {
                    streamReader.Close();
                    streamReader.Dispose();
                }

                webRe.Abort();
                if (webPos != null)
                    webPos.Close();

            }
            if (result.IsSuccess == 1)
            {
                resultLog.Add("status", HttpStatusCode.InternalServerError);
                resultLog.Add("success", false);
                resultLog.Add("responseContent", result.ResponseContent);
                stopwatch.Stop();
                resultLog.Add("elapseTime", stopwatch.Elapsed.TotalMilliseconds);
                string log = JsonConvert.SerializeObject(resultLog);
                Logger.Info(log);
                Logger.Error(log);
            }
            else
            {
                resultLog.Add("status", statusCode);
                resultLog.Add("success", true);
                resultLog.Add("responseContent", result.ResponseContent);
                stopwatch.Stop();
                resultLog.Add("elapseTime", stopwatch.Elapsed.TotalMilliseconds);
                string log = JsonConvert.SerializeObject(resultLog);
                Logger.Info(log);
            }
            return result;
        }

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //總是接受  
        }

        /// <summary>
        /// Get請求
        /// </summary>
        /// <param name="url">請求地址</param>
		/// <param name="traceID">鏈路ID,方便查詢日誌</param>
		/// <param name="markType">請求標識,方便查詢日誌</param>
        /// <returns></returns>
        public HttpRequestEntity Request(string url, string traceID, string markType)
        {
            return BaseRequest(RequestType.Get, url, string.Empty, traceID, markType);
        }

        /// <summary>
        /// Post請求
        /// </summary>
        /// <param name="url">請求地址Url</param>
        /// <param name="requestData">請求內容參數</param>
		/// <param name="traceID">鏈路ID,方便查詢日誌</param>
		/// <param name="markType">請求標識,方便查詢日誌</param>
        /// <returns></returns>
        public HttpRequestEntity Request(string url, string requestData, string traceID, string markType)
        {
            return BaseRequest(RequestType.Post, url, requestData, traceID, markType);
        }

        ~HttpHelper()
        {
            Dispose(false);
        }

        #region IDisposable 成員

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (this._disposable)
                return;

            if (disposing)
            {

            }

            _disposable = true;
        }

        #endregion
    }

    /// <summary>
    /// HttpHelper請求方式
    /// </summary>
    public enum RequestType
    {
        /// <summary>
        /// Get請求
        /// </summary>
        Get,
        /// <summary>
        /// Post請求
        /// </summary>
        Post
    }

    /// <summary>
    /// HttpHelper請求時返回實體
    /// </summary>
    public class HttpRequestEntity
    {
        /// <summary>
        /// 請求是否成功 0-成功(返回Http狀態碼200) 1-失敗(出現異常)
        /// </summary>
        public int IsSuccess { get; set; }
        /// <summary>
        /// 請求返回內容
        /// </summary>
        public string ResponseContent { get; set; }
        /// <summary>
        /// 請求返回內容長度
        /// </summary>
        public long ResponseLength { get; set; }
        /// <summary>
        /// 請求返回編碼類型
        /// </summary>
        public string ResponseEncodingName { get; set; }
    }

調用示例如下:

HttpHelper helper = new HttpHelper();
HttpRequestEntity response = helper.Request("需要訪問的URL", "請求需要的參數", "訪問鏈路ID", "訪問標識");
if (response.IsSuccess != 0)
{
	//程式處理異常,請重試!
}
else
{
	//請求響應成功	
}

 


如對您有幫助勞煩幫忙點個贊,收藏關註一下,相互學習,共同進步。

本文來自博客園,作者:華小睿,轉載請註明原文鏈接:https://www.cnblogs.com/huaxiaorui/p/16658624.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 日誌對程式的重要性不言而喻,輕巧、簡單、無需費腦,程式代碼中隨處可見,幫助我們排查定位一個有一個問題問題。但看似不起眼的日誌,卻隱藏著各式各樣的“坑”,如果使用不當,不僅不能幫助我們,反而會成為服務“殺手”。 本文主要介紹生產環境日誌使用不當導致的“坑”及避坑指北,高併發系統下尤為明顯。同時提供一套... ...
  • IO流 筆記目錄:(https://www.cnblogs.com/wenjie2000/p/16378441.html) IO流體系圖 文件 什麼是文件 文件.對我們並不陌生,文件是==保存數據的地方==,比如大家經常使用的word文檔,txt文件.excel文件...都是文件。它既可以保存一張圖 ...
  • django的基本操作 1.django的安裝 (1)在ubuntu上的安裝 sudo pip3 install django==2.1.12(版本號) 檢查安裝是否成功: sudo pip3 freeze|grep -i ‘Django' 有輸出django==2.2.12 表示安裝成功 (2)在 ...
  • Golang只有二十五個系統保留關鍵字,二十幾個系統內置函數,加起來只有五十個左右需要記住的關鍵字,縱觀編程宇宙,無人能出其右。其中還有一些保留關鍵字屬於“錦上添花”,什麼叫錦上添花?就是從錶面上看,就算沒有,也無傷大雅,不影響業務或者邏輯的實現,比如lambda表達式之類,沒有也無所謂,但在初始化 ...
  • 前言 嗨嘍,大家好呀~這裡是愛看美女的茜茜吶 又到了學Python時刻~今天我們來採集一下評論數據! WB態數據抓包+所有的數據提取方式+詞雲圖可視化 開發環境: python 3.8: 解釋器 pycharm: 代碼編輯器 requests 第三方模塊 採集評論代碼 # 導入模塊 import r ...
  • “並行和併發有什麼區別?” 關於這個問題,很多工作5年以上的同學都回答不出來。 或者說,自己有一定的理解,但是不知道怎麼表達。 大家好,我是Mic,一個工作了14年的Java程式員。 關於這個問題,面試官想考察什麼呢? 問題解析 並行和併發最早其實描述的是Java併發編程裡面的概念。 他們強調的是C ...
  • 本文地址:https://blog.csdn.net/qq_40885085 在我們寫代碼的時候,會書寫許多日誌代碼,但是有些敏感數據是需要進行安全脫敏處理的。 對於日誌脫敏的方式有很多,常見的有①使用conversionRule標簽,繼承MessageConverter②書寫一個脫敏工具類,在列印 ...
  • 打開Visual Studio Installer 可以看到vs2022 只支持安裝4.6及以上的版本,如圖所示。那麼該如何安裝4.6以下的版本,下麵將詳細介紹。 安裝4.0~4.5系列 1、在微軟 Visual Studio SDK(https://dotnet.microsoft.com/zh- ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...