前言

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. moviepy用VideoFileClip加载视频时报UnicodeDecodeError: codec cant decode ,No mapping character 错误

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 昨天处理视频时出现了解码错误,通过修改ffmpeg ...

  2. 第15.35节 PyQt编程实战:结合QDial实现的QStackedWidget堆叠窗口程序例子

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.案例说明 本案例是老猿在学习QStackedWidget中的一个测试案例,该案例使用QStack ...

  3. 在 GitHub 玩硬件——GitHub 热点速览 Vol.49

    作者:HelloGitHub-小鱼干 本周的 GitHub Trending 可以说是非常之硬核,天才少年稚晖君的 2 个硬件变装项目荣登热点榜,看完将充电宝改装为显示器的视频,搭配 HDMI-PI ...

  4. IntelliJ IDEA 学习笔记

    之前一直用Eclipse,最近尝试使用IDEA,相较于 Eclipse 而言,IDEA强大的整合能力,比如: Git. Maven. Spring 等:提示功能的快速. 便捷:提示功能的范围广:好用的 ...

  5. 软工团队作业--Scrum冲刺集合贴

    软工团队作业--Scrum冲刺集合贴 团队 团队名称:广东靓仔六强选手 团队成员: 黄清山 黄梓浩 钟俊豪 周立 邓富荣 郑焕 博客链接 Scrum 冲刺 第一篇 Scrum 冲刺 第二篇 Scrum ...

  6. Nodepad++ 没有TextFX Characters插件

    Nodepad++ 没有TextFX Characters插件 原因:从6.5以上的某个版本开始,就没有了默认的这个插件. 我试了最新的版本下载插件也不行,只好下载一个6.4.5的版本,再更新插件管理 ...

  7. 图论补档——KM算法+稳定婚姻问题

    突然发现考前复习图论的时候直接把 KM 和 稳定婚姻 给跳了--emmm 结果现在刷训练指南就疯狂补档.QAQ. KM算法--二分图最大带权匹配 提出问题 (不严谨定义,理解即可) 二分图 定义:将点 ...

  8. 【补题记录】ZJU-ICPC Summer Training 2020 部分补题记录

    补题地址:https://zjusummer.contest.codeforces.com/ Contents ZJU-ICPC Summer 2020 Contest 1 by Group A Pr ...

  9. MarkDown的练习_Java开发学习路径

    MarkDown的练习 语言学习 C/C++语言 Java语言 基础四大件 数据结构与算法 操作系统 计算机网络 设计模式 数据库/SQL 私人令牌:42bb654f53941d5692e98b35f ...

  10. STM32 GPIO输入输出(基于HAL库)

    一.基础认识 GPIO全名为General Purpose Input Output,即通用输入输出.有时候简称为"IO口".通用,说明它是常见的.输入输出,就是说既能当输入口使用 ...