聊一聊声明式接口调用与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;采用三次握手确认建立一个连接&#…

分布式搜索ElasticSearch单机与服务器环境搭建

先到http://www.elasticsearch.org/download/下载最新版的elasticsearch运行包&#xff0c;本文写时最新的是0.19.1&#xff0c;作者是个很勤快的人&#xff0c;es的更新很频繁&#xff0c;bug修复得很快。下载完解开有三个包:bin是运行的脚本&#xff0c;config是设置文件&…

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包</

linux系统服务设置命令--chkconfig命令参数及用法详解

chkconfig(check config) 功能说明&#xff1a;chkconfig命令主要用来更新&#xff08;启动或停止&#xff09;和查询系统服务的运行级信息。谨记chkconfig不是立即自动禁止或激活一个服务&#xff0c;它只是简单的改变了符号连接。 语  法&#xff1a;chkconfig [--add][--…

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

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

查看Nginx,Apache,lighttpd,Mysql,Php的编译参数

查看一些常见服务的在编译安装时的参数&#xff1a; 1.Nginx 编译安装时的参数 [roottest ~]# /usr/local/nginx/sbin/nginx -V nginx version: nginx/0.7.65 built by gcc 4.1.2 20080704 (Red Hat 4.1.2-48) TLS SNI support disabled configure arguments: --userwww --grou…

使用原生js写ajax

// 使用原生js 封装ajax // 兼容xhr对象 function createXHR(){if(typeof XMLHttpRequest ! "undefined"){ // 非IE6浏览器return new XMLHttpRequest();}else if(typeof ActiveXObject ! "undefined"){ // IE6浏览器var version ["MSXML2.XMLHttp…

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 阅读全文 >> 导数公式大全-偏导数基本公式大全_营销/活动策划_计…

在.net 4.0程序中使用TPL Dataflow

今天写了一个小程序&#xff0c;用到了TPL Dataflow&#xff0c;结果在部署的时候发现了一个问题&#xff1a;客户的服务器中有win2003的机器&#xff0c;2003是不支持.net 4.5的&#xff0c;但TPL Dataflow却只能在.net 4.5的程序上使用。 在网上搜了一下&#xff0c;MSDN论坛…

Android之平时遇见的异常和错误总结(不断更新)

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程 安卓错误经验累积 1、当出现下面错误时候 08-21 03:43:16.679: E/AndroidRuntime(1087): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.…

【20120517】【早晨】

今天早上没去GIS程序设计的实验&#xff0c;窝在寝室准备看图论和汇编。。。不多说了&#xff0c;现在开始~~

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;根本…

试题导入mysql乱码_解决Mysql导入乱码问题

解决Mysql导入乱码问题方法一: 通过增加参数 –default-character-set utf8 解决乱码问题C:\Users\Administrator>mysql -uroot -p yktgl < F:\YIKATONG\application\gl.sql --default-character-setutf8方法二: 在命令行导入乱码解决1.mysql>use gl;2.mysql> set…