前言

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. 第3.5节 丰富的Python字典操作

    一. 基本概念 Python提供一种通过名称来访问其各个值的数据结构,这种数据结构称为映射(mapping).字典(dict)是Python中唯一的内置映射类型,其中的值不按顺序排列,而是存储在键下, ...

  2. 第10.5节 使用__all__定义Python模块导入白名单

    一. 引言 <第10.4节 Python模块的弱封装机制>介绍了Python模块的的弱封装机制,除了使用弱封装机制来从一定程度上防止导入特定成员外,Python模块中还提供可另外一种类似白 ...

  3. PyQt(Python+Qt)学习随笔:QTreeWidget中获取指定位置项的itemAt方法

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QTreeWidget的itemAt方法通过视口内的坐标点获取对应坐标位置的项,相关调用方法如下: ...

  4. PyQt(Python+Qt)学习随笔:Qt Designer中toolBar的allowedAreas属性

    1.概述 allowedAreas属性指定工具栏允许移动的范围,其类型为枚举类Qt.ToolBarAreas,有如下取值: 以上取值可以同or操作组合使用. 2.访问方法 缺省值为Qt.AllTool ...

  5. LeetCode初级算法之字符串:7 整数反转

    整数反转 题目地址:https://leetcode-cn.com/problems/reverse-integer/ 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 ...

  6. webpack项目如何正确打包引入的自定义字体?

    一. 如何在Vue或React项目中使用自定义字体 在开发前端项目时,经常会遇到UI同事希望在项目中使用一个炫酷字体的需求.那么怎么在项目中使用自定义字体呢? 其实实现起来并不复杂,可以借用CSS3 ...

  7. bootstrap table 控制checkbox在某些状态不显示

    首先columns:[{field:'column',checkbox:true}];然后设置$("#tableName").bootstrapTable('hideColumn' ...

  8. day013|python之模块02&目录01

    1 from...import 1.1 概念 1.1.1 首次导入模块会发生的事 会触发模块的运行,产生一个模块的名称空间 将运行模块文件过程中产生的名字丢到模块额名称空间 在当前名称空间产生一个名字 ...

  9. mybatis逆向工程运行

    命令: mvn mybatis-generator:generate 项目结构: generatorConfig.xml内容示例 <?xml version="1.0" en ...

  10. STL—— 容器(vector)的数据写入、修改和删除

    1. 通过 push_back() 尾部增加一个元素 : vector 可以通过 "push_back " 写入数据,通过 push_back 可以将数据直接写入至 vector ...