聊一聊声明式接口调用与Nacos的结合使用

背景

对于公司内部的 API 接口,在引入注册中心之后,免不了会用上服务发现这个东西。

现在比较流行的接口调用方式应该是基于声明式接口的调用,它使得开发变得更加简化和快捷。

.NET 在声明式接口调用这一块,有 WebApiClient 和 Refit 可以选择。

前段时间有个群友问老黄,有没有 WebApiClient 和 Nacos 集成的例子。

找了一圈,也确实没有发现,所以只好自己动手了。

本文就以 WebApiClient 为例,简单介绍一下它和 Nacos 的服务发现结合使用。

API接口

基于 .NET 6 创建一个 minimal api。

using Nacos.AspNetCore.V2;var builder = WebApplication.CreateBuilder(args);builder.Services.AddNacosAspNet(x =>
{x.ServerAddresses = new List<string> { "http://localhost:8848/" };x.Namespace = "cs";// 服务名这一块统一用小写!!x.ServiceName = "sample";x.GroupName = "Some_Group";x.ClusterName = "DC_1";x.Weight = 100;x.Secure = false;
});var app = builder.Build();
.
app.MapGet("/api/get", () =>
{return Results.Ok("from .net6 minimal API");
});app.Run("http://*:9991");

这个应用是 provider,在启动的时候,会向 Nacos 进行注册,可以被其他应用发现并调用。

85fff3c294d8449c9a7e48ac56edafcc.png

声明式接口调用

这里同样是创建一个 .NET 6 的 WEB API 项目来演示,这里需要引入一个 nuget 包。

<ItemGroup><PackageReference Include="WebApiClientCore.Extensions.Nacos" Version="0.1.0" />
</ItemGroup>

首先来声明一下这个接口。

// [HttpHost("http://192.168.100.100:9991")]
[HttpHost("http://sample")]
public interface ISampleApi : IHttpApi
{[HttpGet("/api/get")]Task<string> GetAsync();
}

这里其实要注意的就是 HttpHost 这个特性,正常情况下,配置的是具体的域名或者是IP地址。

我们如果需要通过 nacos 去发现这个接口对应的真实地址的话,只需要配置它的服务名就好了。

后面是要进行接口的注册,让这个 ISampleApi 可以动起来。

var builder = WebApplication.CreateBuilder(args);// 添加 nacos 服务发现模块
// 这里没有把当前服务注册到 nacos,按需调整
builder.Services.AddNacosV2Naming(x =>
{x.ServerAddresses = new List<string> { "http://localhost:8848/" };x.Namespace = "cs";
});// 接口注册,启用 nacos 的服务发现功能
// 注意分组和集群的配置
// builder.Services.AddNacosDiscoveryTypedClient<ISampleApi>("Some_Group", "DC_1");
builder.Services.AddNacosDiscoveryTypedClient<ISampleApi>(x => 
{// HttpApiOptionsx.UseLogging = true;
}, "Some_Group", "DC_1");var app = builder.Build();app.MapGet("/", async (ISampleApi api) =>
{var res = await api.GetAsync();return $"client ===== {res}" ;
});app.Run("http://*:9992");

运行并访问 localhost:9992 就可以看到效果了

5cf78872e2994082b7668eea8ecb85a0.png

从上面的日志看,它请求的是 http://sample/api/get,实际上是 http://192.168.100.220:9991/api/get,刚好这个地址是注册到 nacos 上面的,也就是服务发现是生效了。

info: System.Net.Http.HttpClient.ISampleApi.LogicalHandler[100]Start processing HTTP request GET http://sample/api/get
info: System.Net.Http.HttpClient.ISampleApi.ClientHandler[100]Sending HTTP request GET http://sample/api/get
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]Request starting HTTP/1.1 GET http://192.168.100.220:9991/api/get - -
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]Executing endpoint 'HTTP: GET /api/get'

下面来看看 WebApiClientCore.Extensions.Nacos 这个包做了什么。

简单剖析

本质上是加了一个 HttpClientHandler,这个 handler 依赖于 sdk 提供的 INacosNamingService

public static IHttpClientBuilder AddNacosDiscoveryTypedClient<TInterface>(this IServiceCollection services,Action<HttpApiOptions, IServiceProvider> configOptions,string group = "DEFAULT_GROUP",string cluster = "DEFAULT")where TInterface : class, IHttpApi
{NacosExtensions.Common.Guard.NotNull(configOptions, nameof(configOptions));return services.AddHttpApi<TInterface>(configOptions).ConfigurePrimaryHttpMessageHandler(provider =>{var svc = provider.GetRequiredService<INacosNamingService>();var loggerFactory = provider.GetService<ILoggerFactory>();if (svc == null){throw new InvalidOperationException("Can not find out INacosNamingService, please register at first");}return new NacosExtensions.Common.NacosDiscoveryHttpClientHandler(svc, group, cluster, loggerFactory);});
}

在 handler 里面重写了 SendAsync 方法,替换了 HttpRequestMessage 的 RequestUri,也就是把服务名换成了真正的服务地址。

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{var current = request.RequestUri;try{request.RequestUri = await LookupServiceAsync(current).ConfigureAwait(false);var res = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);return res;}catch (Exception e){_logger?.LogDebug(e, "Exception during SendAsync()");throw;}finally{// Should we reset the request uri to current here?// request.RequestUri = current;}
}

具体查找替换逻辑如下:

internal async Task<Uri> LookupServiceAsync(Uri request)
{// Call SelectOneHealthyInstance with subscribe// And the host of Uri will always be lowercase, it means that the services name must be lowercase!!!!var instance = await _namingService.SelectOneHealthyInstance(request.Host, _groupName, new List<string> { _cluster }, true).ConfigureAwait(false);if (instance != null){var host = $"{instance.Ip}:{instance.Port}";// conventions here// if the metadata contains the secure item, will use https!!!!var baseUrl = instance.Metadata.TryGetValue(Secure, out _)? $"{HTTPS}{host}": $"{HTTP}{host}";var uriBase = new Uri(baseUrl);return new Uri(uriBase, request.PathAndQuery);}return request;
}

这里是先查询一个健康的实例,如果存在,才会进行组装,这里有一个关于 HTTPS 的约定,也就是元数据里面是否有 Secure 的配置。

大致如下图:

1b589b3e380723c32c7ab01c3d8b10c3.png

写在最后

声明式的接口调用,对Http接口请求,还是很方便的,可以多试试。

nacos-sdk-csharp 的地址 :https://github.com/nacos-group/nacos-sdk-csharp

nacos-csharp-extensions 的地址:https://github.com/catcherwong/nacos-csharp-extensions

本文示例代码的地址 :https://github.com/catcherwong-archive/2021/tree/main/WebApiClientCoreWithNacos

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/295609.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三次握手和四次挥手图解_三次握手和四次挥手简单理解

TCP三次握手TCP标志位TCP在其协议头中使用大量的标志位或者说1位&#xff08;bit&#xff09;布尔域来控制连接状态&#xff0c;一个包中有可以设置多个标志位。TCP是主机对主机层的传输控制协议&#xff0c;提供可靠的连接服务&#xff0c;采用三次握手确认建立一个连接&#…

Android之基于BaseAdapter和SimpleAdapter的GridView

GridView 第一种方式:用SimpleAdapter 先来贴出本文代码运行的结果: 本文需要添加/修改3个文件:main.xml、night_item.xml、JAVA源代码。 main.xml源代码如下,本身是个GirdView,用于装载Item: <?xml version="1.0" encoding="utf-8"?> <…

IOS开发CAKeyframeAnimation的基本使用与keypath的列举

2019独角兽企业重金招聘Python工程师标准>>> CAKeyframeAnimation跟CABasicAnimation的区别是&#xff1a;CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue)&#xff0c;而CAKeyframeAnimation会使用一个NSArray保存这些数值 - (void)value {CAKe…

少女为什么会身上香香的?

1 一旦接受这个设定苏打窃瓦辛格&#xff08;via.煎甜担担面&#xff09;▼2 有被冒犯到▼3 哈哈哈哈哈▼4 就差了难忘今宵▼5 还是挺在理的▼6 欣慰中带着点点悲伤▼7 原来是你的错▼8 哈哈哈哈哈▼你点的每个赞&#xff0c;我都认真当成了喜欢

Android之Android Studio三种方式导入外部资源 以及 报错处理

Android Studio三种方式导入外部资源 以及 报错处理 android studio提供了三种方式导入外部资源: 1. Library dependency – 在线添加、需联网下载 、 2. File dependency – 从本地添加一些jar包(要先将jar包</

android飞翔的小鸟游戏素材包_开心消消乐×愤怒的小鸟:为开心而战

手机里总有那么一些游戏&#xff0c;是你一旦不小心打开&#xff0c;就完全停不下来的。在这份“一直玩一直爽游戏清单”里&#xff0c;绝对少不了开心消消乐和愤怒的小鸟的身影。神奇的是&#xff0c;在2020的夏天&#xff0c;它们合体了&#xff01;在接到开心消消乐的brief时…

RabbitMQ 处理过慢,原来是一个 SQL 缓存框架导致的 GC 频繁触发

一&#xff1a;背景 1. 讲故事上个月底&#xff0c;有位朋友微信找到我&#xff0c;说他的程序 多线程处理 RabbitMQ 时过慢&#xff0c;帮忙分析下什么原因&#xff0c;截图如下&#xff1a;这问题抛出来&#xff0c;有点懵逼&#xff0c;没说CPU爆高&#xff0c;也没说内存泄…

3部世界顶级宇宙纪录片,献给对宇宙万物充满好奇的你~

全世界只有3.14 % 的人关注了爆炸吧知识宇宙深邃美丽&#xff0c;是黑夜的荧光&#xff0c;是夏天里冒着凉气的西瓜&#xff0c;总是诱人地勾起一代又一代人探索的欲望。对于宇宙思索与探索&#xff0c;人类的脚步从未停止。正是人类对宇宙的好奇&#xff0c;撑起了人类发展的大…

二元函数偏导数公式_偏导数计算公式大全

如果函数f(x)在(a,b)中每一点处都可导,则称f(x)在(a,b)上可导,则可建立f(x)的导函数,简称导数。以下是小学生作文网小编给大家提供的导数公式大全,快来看看吧!导数的定义:当自变量的增量... 2018-12-29 阅读全文 >> 导数公式大全-偏导数基本公式大全_营销/活动策划_计…

OC类

2019独角兽企业重金招聘Python工程师标准>>> OC语言的一个类分为两个文件一个.h&#xff0c;一个.m&#xff0c;.h为头文件用来添加实例变量和方法声明。.m文件里面写入方法的实现 .h一般如下 interface 类名:父类 属性声明 方法声明 end .m一般如下 implementation…

06Prism WPF 入门实战 - Log控件库

1.概要源码及PPT地址&#xff1a;https://github.com/JusterZhu/wemail视频地址&#xff1a;https://www.bilibili.com/video/BV1KQ4y1C7tg?share\sourcecopy\web本章分为以下几个部分来了解&#xff1a;Part1 日志Part1.1 全局异常捕捉Part1.2 DumpPart2 引入控件库2.详细内容…

天冷打字全靠抖?!桌面暖手宝,体验10s速热,温暖升级,冬天有TA就够了

▲点击查看没有一丝丝防备&#xff0c;冷空气说来就来了~无论是寒风猛烈的北方&#xff0c;还是湿冷又没有暖气的南方&#xff0c;对于上班族来说&#xff0c;冬天最痛苦的事情莫过于哆哆嗦嗦在工位码字了&#xff01;冷风侵袭无处不在&#xff0c;备上个暖手袋&#xff0c;根本…

设计模式-Factory Method Pattern

为什么80%的码农都做不了架构师&#xff1f;>>> 一、 工厂方法&#xff08;Factory Method&#xff09;模式 工厂方法&#xff08;FactoryMethod&#xff09;模式是类的创建模式&#xff0c;其用意是定义一个创建产品对象的工厂接口&#xff0c;将实际创建工作推迟…

IoTSharp 2.0 发布

你站在桥上看风景&#xff0c;看风景人在楼上看你。明月装饰了你的窗子&#xff0c;你装饰了别人的梦。喜欢这首诗是因为觉得开源造福了我&#xff0c;我也在尝试贡献自己的力量&#xff0c; 成就他人的同时&#xff0c; 也成就了自己&#xff0c; 贡献开源事业的同时&#xff…

oracle监听

原理 客户端向服务器端发送连接请求&#xff0c;监听器监听到客户端德连接请求监听器监听到客户端德连接请求后&#xff0c;把客户端德连接请求交给数据库服务器处理客户端和服务器端建立连接&#xff0c;连接建立后&#xff0c;服务器端和客户端直接通信&#xff0c;而不再需要…

车窗上为啥总有一些小黑点?没想到居然藏着大作用!

全世界只有3.14 % 的人关注了爆炸吧知识经常坐车的人可能会发现一个小细节车窗边缘有一圈小黑点好多人都以为这个厂家的贴纸反正也不碍事就没去除它其实&#xff0c;这些小黑点确实有真正的科学用途其实并不是所有的车窗都有小黑点也可能是别的形状但是它们都有一个特点——都是…

装饰模式

JAVA23种设计模式之一&#xff0c;英文叫Decorator Pattern&#xff0c;又叫装饰者模式。装饰模式是在不必改变原类文件和使用继承的情况下&#xff0c;动态的扩展一个对象的功能. 1、装饰模式与类继承的区别&#xff1a; 1) 装饰模式是一种动态行为&#xff0c;对已经存在类…

Win11安卓极速教程!

适用于 Android 的 Windows 子系统&#xff08;以下简称“WSA”&#xff09;使你的 Windows 11 电脑能够运行 Android 应用。※ 如何在 Windows 11 上运行 Android 应用此前的教程较为详细&#xff0c;但也繁琐&#xff0c;尤其是 adb 部署部分&#xff0c;不适合新手入门&…

ubuntu12.04 使用gedit 打开txt文件中文乱码的处理方法

2019独角兽企业重金招聘Python工程师标准>>> gedit --encodingGB18030 filename.txt 转载于:https://my.oschina.net/zhangdapeng89/blog/58965

你最擅长哪种数学思维?

全世界只有3.14 % 的人关注了爆炸吧知识许多人会抱怨说&#xff0c;自己没有“数学头脑”。事实上&#xff0c;数学家会以各种各样的方式思考&#xff0c;根本没有所谓的哪种思考数学的方式是正确的。但这很可能造成沟通上的障碍&#xff0c;试想一下&#xff0c;一个用视觉图像…