【C#编程最佳实践 二十二】如何发送带有重试机制的Http请求

简介: 【C#编程最佳实践 二十二】如何发送带有重试机制的Http请求

最近在做的一个功能是通过ESB调用http的client来发送Http请求,学习了相关的调用方式,如何让请求带有重试机制的发送呢?

HttpClient初始化

在整个调用过程中,我们使用到了委托方法的方式,在外层的委托里加入了重试机制以及线程的休眠机制。然后委托调用的方法又分为POST和Get,同时我还使用了返回结果泛型类的方式来定义响应情况,包括成功还是失败的响应状态码。

/// <summary>
    /// 用于访问Rest接口(访问站点的请求)
    /// </summary>
    public class HttpClientHelper
    {
        #region 日志及单例
        protected static readonly LogWrapper Logger = new LogWrapper();
        #endregion 日志及单例
        #region 委托方式进行重试调用
        public static TResult ExecuteFunc<TResult>(Func<TResult> target, int retryCount = 5, int current = 1, int sleepMilliseconds = 0)
        {
            try
            {
                return target.Invoke();
            }
            catch (Exception)
            {
                //超过重试次数后抛出异常
                if (retryCount - current <= 0)
                {
                    throw;
                }
                if (sleepMilliseconds > 0)
                {
                    Thread.Sleep(sleepMilliseconds);
                }
            }
            //递归调用直至超出重试次数后抛出异常
            return ExecuteFunc(target, retryCount, current + 1, sleepMilliseconds);
        }
        #endregion 委托方式进行重试调用
        #region POST及GET请求方法
        /// <summary>
        /// 通过post请求数据
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <typeparam name="TData"></typeparam>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static ApiResult<TResult> Post<TResult, TData>(string url, TData data)
        {
            //获取请求数据
            var value = data == null ? string.Empty : JsonConvert.SerializeObject(data);
            //封装有关个别HTTP请求的所有HTTP特定的信息(上下文信息)
            var content = new StringContent(value, Encoding.UTF8);
            //设置请求头的上下文类型
            content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            //发送Post异步请求信息
            using (var client = new HttpClient())
            {
                //发送异步请求
                var result = client.PostAsync(url, content).Result;
                //获取请求返回的结果数据并将其序列化为字符串
                var response = result.Content.ReadAsStringAsync().Result;
                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new HttpRequestException($"调用接口:{url}报错,StatusCode:{result.StatusCode},Msg:{response}");
                //将返回结果反序列化为指定Model
                return JsonConvert.DeserializeObject<ApiResult<TResult>>(response);
            }
        }
        /// <summary>
        /// 通过Get方式请求数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="url"></param>
        /// <returns></returns>
        public static ApiResult<T> Get<T>(string url)
        {
            //发送Get异步请求信息
            using (var client = new HttpClient())
            {
                //发送异步请求
                var result = client.GetAsync(url).Result;
                //获取请求返回的结果数据并将其序列化为字符串
                var response = result.Content.ReadAsStringAsync().Result;
                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new HttpRequestException($"调用接口:{url}报错,StatusCode:{result.StatusCode},Msg:{response}");
                //将返回结果反序列化为指定Model
                return JsonConvert.DeserializeObject<ApiResult<T>>(response);
            }
        }
        #endregion POST及GET请求方法
    }
    /// <summary>
    /// 返回结果类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ApiResult<T>
    {
        private static readonly string SUCCESS = "200";
        private static readonly string FAIL = "500";
        public string Code { get; set; }
        public string Message { get; set; }
        public T Data { get; set; }
        public int Total { get; set; }
        /// <summary>
        /// 访问成功
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static ApiResult<T> Success(T data)
        {
            return new ApiResult<T>()
            {
                Data = data,
                Code = SUCCESS
            };
        }
        /// <summary>
        /// 访问失败
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static ApiResult<T> Fail(string message)
        {
            return new ApiResult<T>()
            {
                Code = FAIL,
                Message = message
            };
        }

接口调用

在定义好了HttpClient之后,我们就可以通过接口调用的方式来启动对站点的访问了,这部分因为我们的环境不同,所以域名需要不同,所以域名就需要通过配置来读取:

//封装url请求Model,用于填充到POST请求的body里
var urlModel = new UrlModel()
 {
    tenantId = tenantId,
    appName = appName,
    api_key = ApiKey
  };      
var url = $"{HOST}/tmlapi/tmlRequest?&tenantId={tenantId}&appName={appName}&api_key={ApiKey}";
//开启http客户端发送Post请求
var result = HttpClientHelper.ExecuteFunc<ApiResult<string>>(() => HttpClientHelper.Post<string, UrlModel>(url, urlModel));

在这个过程中我们设计好body里要放置的POST请求所需参数并将其放置到一个model里,然后依据配置读取域名并拼接好url,把应该放置到query里的参数拼接到url上,连同model一起传入HttpClient方法中。需要特别注意的是如果是POST请求,那么定义在body里的请求参数要放到一个model里传进去,而定义为query的请求参数必须拼接到url上传入,如果定义为query,再放到body里来是会导致缺少参数请求不通的。

总而言之,需要调用HttpClient的时候,一定要封装一层方法,然后做重试机制的处理,毕竟是访问站点。还要注意参数的传递形式!

相关文章
|
18天前
|
Java
java原生发送http请求
java原生发送http请求
|
25天前
|
网络协议 Linux iOS开发
推荐:实现RTSP/RTMP/HLS/HTTP协议的轻量级流媒体框架,支持大并发连接请求
推荐:实现RTSP/RTMP/HLS/HTTP协议的轻量级流媒体框架,支持大并发连接请求
56 1
|
1月前
|
编解码 测试技术 索引
性能工具之 Jmeter 使用 HTTP 请求编写 HLS 脚本
在我们简要介绍了 HLS 协议的基础知识,接下来我们详细介绍一种使用 Jmeter 编写压测 HLS 协议脚本的方法。
73 1
性能工具之 Jmeter 使用 HTTP 请求编写 HLS 脚本
|
7天前
|
安全 Java 网络安全
Servlet 教程 之 Servlet 客户端 HTTP 请求 2
Servlet教程介绍了如何在Servlet中处理HTTP请求,包括获取Cookie、头信息、参数、Session等。方法如:`getCookies()`、`getAttributeNames()`、`getHeaderNames()`、`getParameterNames()`等。还能获取身份验证类型、字符编码、MIME类型、请求方法、远程用户信息、URL路径、安全通道状态以及请求内容长度等。此外,可通过`getSession()`创建或获取Session,并以`Map`形式获取参数。
21 8
|
1天前
|
存储 缓存 开发框架
Flutter的网络请求:使用Dart进行HTTP请求的技术详解
【4月更文挑战第26天】了解Flutter网络请求,本文详述使用Dart进行HTTP请求
|
2天前
|
JSON 数据格式 索引
ES 查看索引的属性的http请求
在 Elasticsearch 中,要查看索引的属性,可以通过发送 HTTP 请求来执行以下操作: 1. **获取索引的映射(Mapping)**: 可以使用 `GET` 请求访问 Elasticsearch 的 `_mapping` 端点来获取特定索引的映射信息。 示例请求: ```http GET http://<elasticsearch_host>:<port>/<index_name>/_mapping ``` 2. **获取索引的设置(Settings)**: 可以使用 `GET` 请求访问 Elasticsearch 的 `_setting
|
3天前
|
JSON 测试技术 API
Python的Api自动化测试使用HTTP客户端库发送请求
【4月更文挑战第18天】在Python中进行HTTP请求和API自动化测试有多个库可选:1) `requests`是最流行的选择,支持多种请求方法和内置JSON解析;2) `http.client`是标准库的一部分,适合需要低级别控制的用户;3) `urllib`提供URL操作,适用于复杂请求;4) `httpx`拥有类似`requests`的API,提供现代特性和异步支持。根据具体需求选择,如多数情况`requests`已足够。
9 3
|
6天前
|
存储 安全 网络安全
C#编程的安全性与加密技术
【4月更文挑战第21天】C#在.NET框架支持下,以其面向对象和高级特性成为安全软件开发的利器。本文探讨C#在安全加密领域的应用,包括使用System.Security.Cryptography库实现加密算法,利用SSL/TLS保障网络传输安全,进行身份验证,并强调编写安全代码的重要性。实际案例涵盖在线支付、企业应用和文件加密,展示了C#在应对安全挑战的同时,不断拓展其在该领域的潜力和未来前景。
|
6天前
|
程序员 C#
C#编程中的面向对象编程思想
【4月更文挑战第21天】本文探讨了C#中的面向对象编程,包括类、对象、封装、继承和多态。类是对象的抽象,定义属性和行为;对象是类的实例。封装隐藏内部细节,只暴露必要接口。继承允许类复用和扩展属性与行为,而多态使不同类的对象能通过相同接口调用方法。C#通过访问修饰符实现封装,使用虚方法和抽象方法实现多态。理解并应用这些概念,能提升代码的清晰度和可扩展性,助你成为更好的C#程序员。
|
7天前
|
IDE 程序员 C#
C#编程入门:从零开始的旅程
【4月更文挑战第20天】本文引导初学者入门C#编程,从环境搭建开始,推荐使用Visual Studio Community版作为IDE。接着,通过编写&quot;Hello, World!&quot;程序,介绍基本语法,包括数据类型、运算符和表达式。文章还涉及控制结构、函数和方法,以及面向对象编程概念。通过学习,读者将对C#有初步了解,并激发进一步探索编程世界的兴趣。