【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的时候,一定要封装一层方法,然后做重试机制的处理,毕竟是访问站点。还要注意参数的传递形式!

相关文章
|
6天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
|
13天前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
28 3
|
1月前
|
Rust 前端开发 API
Tauri 开发实践 — Tauri HTTP 请求开发
本文介绍了如何在 Tauri 中发起 HTTP 请求。首先通过安装 Tauri 生态中的工具包并配置 `tauri.conf.json` 文件来允许特定域名的 HTTP 通信。接着封装了一个简单的 HTTP 客户端类,并在页面中使用该客户端实现 GET 和 POST 请求。最后提供了完整的源码地址以供参考。此功能使得桌面应用能够与远程服务器进行交互,增强了应用的实用性。
86 1
Tauri 开发实践 — Tauri HTTP 请求开发
|
16天前
|
缓存 前端开发 API
|
21天前
|
数据采集 前端开发 算法
Python Requests 的高级使用技巧:应对复杂 HTTP 请求场景
本文介绍了如何使用 Python 的 `requests` 库应对复杂的 HTTP 请求场景,包括 Spider Trap(蜘蛛陷阱)、SESSION 访问限制和请求频率限制。通过代理、CSS 类链接数控制、多账号切换和限流算法等技术手段,提高爬虫的稳定性和效率,增强在反爬虫环境中的生存能力。文中提供了详细的代码示例,帮助读者掌握这些高级用法。
Python Requests 的高级使用技巧:应对复杂 HTTP 请求场景
|
4天前
|
JSON API 数据格式
Python中获取HTTP请求响应体的详解
本文介绍了如何使用Python的`requests`和`urllib`库发送HTTP请求并处理响应体。`requests`库简化了HTTP请求过程,适合快速开发;`urllib`库则更为底层,适用于性能要求较高的场景。文章详细演示了发送GET请求、处理JSON响应等常见操作。
|
3天前
|
安全 API 网络安全
使用OkHttp进行HTTPS请求的Kotlin实现
使用OkHttp进行HTTPS请求的Kotlin实现
|
10天前
|
前端开发 JavaScript Java
如何捕获和处理HTTP GET请求的异常
如何捕获和处理HTTP GET请求的异常
|
12天前
|
开发者
HTTP 协议请求方法的发展历程
【10月更文挑战第21天】
|
12天前
|
安全
HTTP 协议的请求方法
【10月更文挑战第21天】

热门文章

最新文章