草庐IT

C#实现HTTP访问类HttpHelper

华小睿的笔记 2023-03-28 原文

在项目开发过程中,我们经常会访问第三方接口,如我们需要接入的第三方接口是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
{
	//请求响应成功	
}

 


如对您有帮助劳烦帮忙点个赞,收藏关注一下,相互学习,共同进步。

有关C#实现HTTP访问类HttpHelper的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  3. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  4. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  5. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  6. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  7. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  8. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  9. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  10. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

随机推荐