Refit集成consul在asp.net core中的实践
前言
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中的实践的更多相关文章
- Refit在ASP.NET Core中的实践
前言 声名式服务调用,己经不算是一个新鲜的话题了,毕竟都出来好些年了. 下面谈谈,最近项目中用到一个这样的组件的简单实践. 目前部分项目用到的是Refit这个组件,都是配合HttpClientFact ...
- Api网关Kong集成Consul做服务发现及在Asp.Net Core中的使用
写在前面 Api网关我们之前是用 .netcore写的 Ocelot的,使用后并没有完全达到我们的预期,花了些时间了解后觉得kong可能是个更合适的选择. 简单说下kong对比ocelot打动我的 ...
- [翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置
[翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置 原文: USING CONSUL FOR STORING THE CONFIGURATION IN ASP.NET COR ...
- 在 ASP.NET Core 中集成 Skywalking APM
前言 大家好,今天给大家介绍一下如何在 ASP.NET Core 项目中集成 Skywalking,Skywalking 是 Apache 基金会下面的一个开源 APM 项目,有些同学可能会 APM ...
- 在Asp.Net Core中集成Kafka
在我们的业务中,我们通常需要在自己的业务子系统之间相互发送消息,一端去发送消息另一端去消费当前消息,这就涉及到使用消息队列MQ的一些内容,消息队列成熟的框架有多种,这里你可以读这篇文章来了解这些MQ的 ...
- 如何简单的在 ASP.NET Core 中集成 JWT 认证?
前情提要:ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统 文章超长预警(1万字以上),不想看全部实现过程的同学可以直接跳转到末尾查看成果或者一键安装相关的 nuget 包 自上一 ...
- 在Asp.Net Core中集成Kafka(中)
在上一篇中我们主要介绍如何在Asp.Net Core中同步Kafka消息,通过上一篇的操作我们发现上面一篇中介绍的只能够进行简单的首发kafka消息并不能够消息重发.重复消费.乐观锁冲突等问题,这些问 ...
- 如何在 ASP.NET Core 中发送邮件
前言 我们知道目前 .NET Core 还不支持 SMTP 协议,当我么在使用到发送邮件功能的时候,需要借助于一些第三方组件来达到目的,今天给大家介绍两款开源的邮件发送组件,它们分别是 MailKit ...
- Ubuntu & Docker & Consul & Fabio & ASP.NET Core 2.0 微服务跨平台实践
相关博文: Ubuntu 简单安装 Docker Mac OS.Ubuntu 安装及使用 Consul Consul 服务注册与服务发现 Fabio 安装和简单使用 阅读目录: Docker 运行 C ...
随机推荐
- 转:http协议学习系列(响应头---Response Headers)
HTTP最常见的响应头如下所示: ·Allow:服务器支持哪些请求方法(如GET.POST等): ·Content-Encoding:文档的编码(Encode)方法.只有在解码之后才可以得到Conte ...
- Python中使用“模块名.__all__”查看模块建议导出的属性
在<第10.5节 使用__all__定义Python模块导入白名单>中,老猿介绍了在自定义模块中使用定义__all__属性来提供模块对外可见的白名单,使用该机制除了可以定义访问的白名单外, ...
- csv 如何将txt文件转换成csv文件
import csvdef convert_txt_to_csv(out_file_path, input_file_path, txt_sep): #定义输出路径,输入文件路径,txt的分隔符 wi ...
- 小程序image无法显示图片
图片路径中有中文 图片地址为http开头,图片只能在调试模式中显示,真机也必须开调试. 图片名称有空格 图片的后缀必须为小写的.png或者.jpg
- redis学习之——在分布式数据库中CAP原理CAP+BASE
分布式系统 分布式系统(distributed system) 由多台计算机和通信的软件组件通过计算机网络连接(本地网络或广域网)组成.分布式系统是建立在网络之上的软件系统.正是因为软件的特性,所以分 ...
- EasyX 简易绘图工具接口整理
EasyX Library for C++ (Ver:20190415(beta)) http://www.easyx.cn EasyX.h 1 #pragma once 2 3 #ifndef ...
- react项目中的一些配置
react中事件优化使用babel插件 npm install babel-plugin-react-scope-binding --save-dev react中绝对路径引入文件:在根目录下增加js ...
- OGG报错:Cannot load ICU resource bundle 'ggMessage', error code 2 - No such file or directory
[oracle@dgdb1 ~]$ ggsci Oracle GoldenGate Command Interpreter for OracleVersion 11.2.1.0.3 14400833 ...
- jenkins+ant+jmeter实现自动化集成(详解)
jenkins+ant+jmeter实现自动化集成 for window 一.jmeter 1.jmeter安装 二.ant 1.ant安装 三.ant运行 jmeter脚本 1.配置 四.jenki ...
- SSO的通用标准OpenID Connect
目录 简介 OpenID Connect是什么 ID Token 请求ID Token ID Token可以做什么 Open Connect认证码授权的例子 User Info 简介 OpenID C ...