HttpClientFactory与Steeltoe结合来完成服务发现
前言
上一篇说了一下用HttpClientFactory实现了简单的熔断降级。
这篇就来简单说说用HttpClientFactory来实现服务发现。由于标题已经好明显的说了Steeltoe
因此这里会要求有Spring Clound的相关环境,本文也默认各位对这里有些许了解,所以不会涉及搭建过程的。
下面就开始正文了。
定义Service
这里的Service,其实可以比较简单的理解成对注册到Eureka的服务进行调用,然后进行后续处理。
public interface IMyService
{
Task<string> GetTextAsync();
}
public class MyService : IMyService
{
private readonly ILogger _logger;
private readonly HttpClient _httpClient;
private const string MY_URL = "";
public MyService(HttpClient httpClient, ILoggerFactory logFactory)
{
_logger = logFactory.CreateLogger<MyService>();
_httpClient = httpClient;
}
public async Task<string> GetTextAsync()
{
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, MY_URL);
var responseMessage = await _httpClient.SendAsync(requestMessage);
var result = await responseMessage.Content.ReadAsStringAsync();
_logger.LogInformation("GetTextAsync: {0}", result);
return result;
}
}
在上面的Service中,都是常规的不能再常规的HttpClient的用法!似乎也没有看到任何和服务发现相关的东西呀。
确实,就上面的代码,完成不了服务发现,因为我们的主角,HttpClientFactory还没有出场!
先定义好这个Service,是因为我们这里要用另一种client方式(Typed Client)。
下面就去Startup进行相关的配置了。
在Startup进行配置
在进行配置之前,我们要先添加Steeltoe.Discovery.ClientCore的引用。
<PackageReference Include="Steeltoe.Discovery.ClientCore" Version="2.1.0-rc1" />
再按照Steeltoe的配置说明,在appsettings.json
中添加下面的配置
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Error"
}
},
"AllowedHosts": "*",
"spring": {
"application": {
"name": "clienttest"
}
},
"eureka": {
"client": {
"serviceUrl": "http://192.168.1.133:7070/eureka/",
"shouldFetchRegistry": true,
"ValidateCertificates": false
},
"instance": {
"port": 7788,
"instanceId": "192.168.1.116:7788",
"hostName": "192.168.1.116"
}
}
}
最后就是在ConfigureServices
方法里面进行操作了。
public void ConfigureServices(IServiceCollection services)
{
//服务发现客户端
services.AddDiscoveryClient(Configuration);
//服务发现的Handler
services.AddTransient<DiscoveryHttpMessageHandler>();
//HttpClient
services.AddHttpClient("my", c =>
{
c.BaseAddress = new Uri("http://bservicetest/api/values/");
})
.AddHttpMessageHandler<DiscoveryHttpMessageHandler>()
.AddTypedClient<IMyService, MyService>();
//2.1
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
这里注册HttpClient,涉及到了两个点。一个是Typed Client,另一个是outgoing request middleware。
Typed Client 主要是AddTypedClient<IMyService, MyService>()
,表明注册的这个HttpClient是给这个类型用的。
DiscoveryHttpMessageHandler表明,使用这个HttpClient的时候,会使用这个Handler.
另外,这里指定的BaseAddress是http://bservicetest/api/values/。
这个是已经注册到Eureka的另外一个测试服务,我们就是要发现它,然后从这个服务里面取到结果。
然后,自然就是控制器了。
Controller和日志使用
Controller就是很简单的了,不需要多说。
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values/text
[HttpGet("text")]
public async Task<string> GetTextAsync([FromServices]Services.IMyService service)
{
return await service.GetTextAsync();
}
}
这里还加了一个日志,是为了方便发布后查看日志,所以添加了NLog来输出日志。
添加一个nlog.config
,内容大致如下。
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
throwConfigExceptions="true">
<!-- the targets to write to -->
<targets>
<target xsi:type="File"
name="archive"
archiveEvery="Day"
archiveFileName = "test-{########}.log"
archiveNumbering = "Date"
archiveDateFormat = "yyyyMMdd"
maxArchiveFiles = "4"
fileName="logs/test.log"
layout="${longdate}|${level:uppercase=true}|${logger}|${message}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<!--All logs, including from Microsoft-->
<logger name="*" minlevel="Info" writeTo="archive" />
<logger name="Microsoft.*" minlevel="Error" writeTo="archive" final="true" />
</rules>
</nlog>
然后在Program
添一行使用NLog的代码。
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseNLog();
}
运行效果
发布之后,可以看到Eureka上面已经成功注册了我们的这个ClientTest服务
其中,上图两个箭头的地方就是我们用到的服务,CLIENTTEST就是我们刚才发布的。BSERVICETEST是另一个测试服务。
CLIENTTEST就是会调用BSERVICETEST这个测试服务拿数据。
下面请求看看效果。
从动图来看,是已经达到预期了,由于BSERVICETEST有两个实例,所以也可以看到上面的结果是,两个实例在随机返回结果。
最后看看日志
请求也确实是到了我们的BSERVICETEST,而不是直接通过这个service的直接地址去访问的。
总结
Outgoing request middleware这个功能对HttpClientFactoty来说,用途似乎不少,就看各位怎么发挥了。
Steeltoe团队似乎也在尝试将Hystrix以HttpClientFactoty的形式来调用。对比Polly,就个人而言,还是觉得Polly好用一点。
最后附上本文的示例代码