前言

github:https://github.com/alphayu/

Refit、WebApiClient、Feign等都是支持声名式的Restful服务调用的开源组件。

这个几个组件都综合研究总结了下,Refit fork数多,使用文档易懂,提供的功能基本都满足我的要求。

同时Refit本身集成了HttpClientFactory(Refit.HttpClientFactory)。

综上最后还是选择了Refit。

然而我的项目是使用Consul作为服务注册中心。

Refit、WebApiClient、Feign 这个几个.Net core 社区比较流行的http客户端Restful资源请求组件都没有集成Consul服务发现功能。

Steeltoe扩展了Refit的Euerka的服务发现,配合Refit.HttpClientFactory可以很好的声明服务调用。

在google搜索了下Refit consul关键字,搜索出来的基本都是介绍Refit与Consul的基础使用的文章。

看来只有靠自己造个轮子了。

研究了下Steeltoe组件Refit的Euerka的服务发现。

要集成Consul需要实现一个ConsulHttpMessageHandler,看了下Steeltoel的DiscoveryHttpMessageHandler类代码,关联的文件太多,借鉴它的写法太麻烦了。

原本想放弃了,接着研究了下Refit的相关代码与httpclientfactory相关文章,豁然开朗。

原来很容易实现,只是自己之前没有看懂而已。

只需写一个类继承DelegatingHandler类,覆写SendAsync方法,并把该类注册进去替换缺省的HttpMessageHandler。

核心代码

namespace RefitConsul
{
public class ConsulDiscoveryDelegatingHandler : DelegatingHandler
{
private readonly ConsulClient _consulClient;
private readonly Func<Task<string>> _token;
public ConsulDiscoveryDelegatingHandler(string consulAddress
, Func<Task<string>> token = null)
{
_consulClient = new ConsulClient(x =>
{
x.Address = new Uri(consulAddress);
});
       //获取token的方法,可选参数
_token = token;
} protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request
, CancellationToken cancellationToken)
{
var current = request.RequestUri;
var cacheKey = $"service_consul_url_{current.Host }";
try
{
          //如果声明接口有验证头,在这里统一处理。
var auth = request.Headers.Authorization;
if (auth != null)
{
if (_token == null) throw new ArgumentNullException(nameof(_token)); var tokenTxt = await _token();
request.Headers.Authorization = new AuthenticationHeaderValue(auth.Scheme, tokenTxt);
}

          //服务地址缓存3秒
var serverUrl = CacheManager.GetOrCreate<string>(cacheKey, entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(3);
return LookupService(current.Host);
}); request.RequestUri = new Uri($"{current.Scheme}://{serverUrl}{current.PathAndQuery}");
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
CacheManager.Remove(cacheKey);
throw;
}
finally
{
request.RequestUri = current;
}
} private string LookupService(string serviceName)
{
//根据服务名获取服务地址
var servicesEntry = _consulClient.Health.Service(serviceName, string.Empty, true).Result.Response;
if (servicesEntry != null && servicesEntry.Any())
{
          //目前只实现了随机轮询
int index = new Random().Next(servicesEntry.Count());
var entry = servicesEntry.ElementAt(index);
return $"{entry.Service.Address}:{entry.Service.Port}";
}
return null;
}
}
}

如何使用

Refit的基本用法就不记录了,重点写Refit集成Consul如何写代码。

1、定义一个服务接口

    public interface IAuthApi
{
/// <summary>
/// 不需要验证的接口
/// </summary>
/// <returns></returns>
[Get("/sys/users")]
Task <dynamic> GetUsers(); /// <summary>
/// 接口采用Bearer方式验证,Token在ConsulDiscoveryDelegatingHandler统一获取
/// </summary>
/// <returns></returns>
[Get("/sys/session")]
[Headers("Authorization: Bearer")]
Task<dynamic> GetCurrentUserInfo(); /// <summary>
/// 接口采用Bearer方式验证,Token使用参数方式传递
/// </summary>
/// <returns></returns>
[Get("/sys/session")]
Task<dynamic> GetCurrentUserInfo([Header("Authorization")] string authorization);
}

2、在startup文件中注册Refit组件

        public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(); //重试策略
var retryPolicy = Policy.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(response => response.StatusCode== System.Net.HttpStatusCode.BadGateway)
.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
});
//超时策略
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(5);
//隔离策略
var bulkheadPolicy = Policy.BulkheadAsync<HttpResponseMessage>(10, 100);
//回退策略
//断路策略
var circuitBreakerPolicy = Policy.Handle<Exception>()
.CircuitBreakerAsync(2, TimeSpan.FromMinutes(1));
//注册RefitClient
//用SystemTextJsonContentSerializer替换默认的NewtonsoftJsonContentSerializer序列化组件
//如果调用接口是使用NewtonsoftJson序列化则不需要替换
services.AddRefitClient<IAuthApi>(new RefitSettings(new SystemTextJsonContentSerializer()))
//设置服务名称,andc-api-sys是系统在Consul注册的服务名
.ConfigureHttpClient(c => c.BaseAddress = new Uri("http://andc-api-sys"))
//注册ConsulDiscoveryDelegatingHandler,
.AddHttpMessageHandler(() =>
{
//http://12.112.75.55:8550是consul服务器的地址
//() => Helper.GetToken() 获取token的方法,是可选参数,如果不需要token验证不需要传递。
return new ConsulDiscoveryDelegatingHandler("http://12.112.75.55:8550", () => Helper.GetToken());
})
//设置httpclient生命周期时间,默认也是2分钟。
.SetHandlerLifetime(TimeSpan.FromMinutes(2))
//添加polly相关策略
.AddPolicyHandler(retryPolicy)
.AddPolicyHandler(timeoutPolicy)
.AddPolicyHandler(bulkheadPolicy);
}

3、如何在controller中调用

    public class HomeController : ControllerBase
{
private readonly IAuthApi _authApi;
private readonly string _token = Helper.GetToken().Result; /// <summary>
/// RefitConsul测试
/// </summary>
/// <param name="authApi">IAuthApi服务</param>
public HomeController(IAuthApi authApi)
{
_authApi = authApi;
} [HttpGet]
public async Task<dynamic> GetAsync()
{
//不需要验证的服务
var result1 = await _authApi.GetUsers(); //需要验证,token采用参数传递
var result2 = await _authApi.GetCurrentUserInfo($"Bearer {_token}"); //需要验证,token在ConsulDiscoveryDelegatingHandler获取。
var result3 = await _authApi.GetCurrentUserInfo(); return result3;
}
}

Refit集成consul在asp.net core中的实践的更多相关文章

  1. Refit在ASP.NET Core中的实践

    前言 声名式服务调用,己经不算是一个新鲜的话题了,毕竟都出来好些年了. 下面谈谈,最近项目中用到一个这样的组件的简单实践. 目前部分项目用到的是Refit这个组件,都是配合HttpClientFact ...

  2. Api网关Kong集成Consul做服务发现及在Asp.Net Core中的使用

    写在前面   Api网关我们之前是用 .netcore写的 Ocelot的,使用后并没有完全达到我们的预期,花了些时间了解后觉得kong可能是个更合适的选择. 简单说下kong对比ocelot打动我的 ...

  3. [翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置

    [翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置 原文: USING CONSUL FOR STORING THE CONFIGURATION IN ASP.NET COR ...

  4. 在 ASP.NET Core 中集成 Skywalking APM

    前言 大家好,今天给大家介绍一下如何在 ASP.NET Core 项目中集成 Skywalking,Skywalking 是 Apache 基金会下面的一个开源 APM 项目,有些同学可能会 APM ...

  5. 在Asp.Net Core中集成Kafka

    在我们的业务中,我们通常需要在自己的业务子系统之间相互发送消息,一端去发送消息另一端去消费当前消息,这就涉及到使用消息队列MQ的一些内容,消息队列成熟的框架有多种,这里你可以读这篇文章来了解这些MQ的 ...

  6. 如何简单的在 ASP.NET Core 中集成 JWT 认证?

    前情提要:ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统 文章超长预警(1万字以上),不想看全部实现过程的同学可以直接跳转到末尾查看成果或者一键安装相关的 nuget 包 自上一 ...

  7. 在Asp.Net Core中集成Kafka(中)

    在上一篇中我们主要介绍如何在Asp.Net Core中同步Kafka消息,通过上一篇的操作我们发现上面一篇中介绍的只能够进行简单的首发kafka消息并不能够消息重发.重复消费.乐观锁冲突等问题,这些问 ...

  8. 如何在 ASP.NET Core 中发送邮件

    前言 我们知道目前 .NET Core 还不支持 SMTP 协议,当我么在使用到发送邮件功能的时候,需要借助于一些第三方组件来达到目的,今天给大家介绍两款开源的邮件发送组件,它们分别是 MailKit ...

  9. Ubuntu & Docker & Consul & Fabio & ASP.NET Core 2.0 微服务跨平台实践

    相关博文: Ubuntu 简单安装 Docker Mac OS.Ubuntu 安装及使用 Consul Consul 服务注册与服务发现 Fabio 安装和简单使用 阅读目录: Docker 运行 C ...

随机推荐

  1. PyQt(Python+Qt)学习随笔:富文本编辑器QTextEdit功能详解

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.概述 QTextEdit是一个高级的所见即所得的文档查看器和编辑器 ...

  2. PyQt(Python+Qt)学习随笔:QToolBox工具箱的currentItemName和tabSpacing属性

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 在Designer中,toolBox的属性中有currentItemName和tabSpacing属 ...

  3. Python正则表达式处理中的匹配对象是什么?

    老猿才开始学习正则表达式处理时,对于搜索返回的匹配对象这个名词不是很理解,因此在前阶段<第11.3节 Python正则表达式搜索支持函数search.match.fullmatch.findal ...

  4. LeetCode初级算法之数组:26 删除排序数组中的重复项

    删除排序数组中的重复项 题目地址:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ 给定一个排序数组,你需要在 ...

  5. Win10新增API

    Win10新增API为以下一些方面: Windows.AI Windows.ApplicationModel Windows.Devices Windows.Globalization Windows ...

  6. 【题解】「AT4303」[ABC119D] Lazy Faith

    AT4303 [ABC119D] Lazy Faith[题解][二分] AT4303 translation 有 \(a\) 个点 \(s\),有 \(b\) 个点 \(t\),问从点 \(x\) 出 ...

  7. 二叉排序树(BST)

    二叉排序树(BST) 二叉排序树,又称二叉查找树(BST) 左子树结点值<根节点值<右子树结点值 如果用中序遍历来遍历一棵二叉排序树的话,可以得到一个递增的有序数列 左根右 二叉排序树的查 ...

  8. Shell脚本命令常用技巧

    如果一个命令只有一次输出,但想持续观察输出变化,使用watch -d -n1 'df -h'可行,df -h输出一次硬盘使用情况,用上面指令可以持续观察.-d表示相邻输出如果有差异要高亮标记,-n1表 ...

  9. [日常摸鱼]Vijos1083小白逛公园-线段树

    题意:单点修改,询问区间最大子段和,$n\leq 5e5$ 考虑分治的方法$O(nlogn)$求一次最大子段和的做法,我们是根据中点分成左右两个区间,那么整个区间的答案要么是左边答案,要么是右边答案, ...

  10. java基础模拟考试三套试卷

    卷1: 一.单选题(15道,共30分) //1.下列关于JDK.JRE.JVM关系描述正确的是 (A) A:JDK是开发工具,包含了JRE.JRE是运行环境,包含了JVM.JVM是虚拟机,可以保证跨平 ...