使用 Yarp 做网关(二) : 网关 Swagger
作者:互联网
Yarp & Swagger
目录接着上一节 使用 Yarp 做网关 (一),
完成上一节的练习后,还遗留了一个问题:
如何通过 YarpGateway 访问内部服务的Swagger呢?
问题:无法访问内部服务 Swagger
外部访问 IdentityService 和 OrderService 是通过 网关:YarpGateway 访问的,使用者这个并不知道这个两个服务的具体地址,也就是不知道如何访问它们的 Swagger,那么:
如何通过 YarpGateway 访问这两个服务的Swagger呢?
实现原理
使用网关内部服务的 Swagger 信息,其地址为:
http://ip:port/swagger/v1/swagger.json
例如,OrderService 服务的 Swagger 信息为:
http://localhost:7721/swagger/v1/swagger.json
在网关中使用内部服务的 Swagger 终点,再注册 Swagger 终点。
访问 OrderService 服务的 Swagger 信息地址:http://localhost:7711/swagger/v1/swagger.json
返回如下信息:(只列举部分数据)
{ "openapi": "3.0.1", "info": { "title": "Identity Service", "version": "v1" }, "paths": { "/api/identity/users": { "get": { "tags": [ "User" ], "responses": { "200": { "description": "Success", "content": { "text/plain": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/IdentityService.Models.User" } } }, "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/IdentityService.Models.User" } } }, "text/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/IdentityService.Models.User" } } } } } } }, .....
内部服务支持跨域
网关要请求内部服务的Swagger 信息,这是跨域请求,所以要求两个服务支持对网关的跨域请求。
在IdentityService 和 OrderService 项目中都做如下修改:
添加跨域配置
在 appsettins.json
文件中添加跨域配置:
{
"App": {
"CorsOrigins": "http://localhost:7700" // 网关地址,支持网关的Yarp gatewary跨域请求
}
}
其中,这个地址http://localhost:7700 就是网关的地址。
支持跨域
修改 Program.cs
文件:
代码清单:IdentityService/Program.cs
代码清单:OrderService/Program.cs
......
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder
.WithOrigins(
configuration["App:CorsOrigins"]
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.ToArray()
)
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
......
app.UseRouting();
+ app.UseCors(); // 添加跨域支持
app.UseSwagger();
app.UseSwaggerUI();
.....
网关添加 Swagger
在网关项目【YarpGateway】中做如下修改:
代码清单:YarpGateway/Program.cs
builder.Services.AddControllers(); //Web MVC
......
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "Order Service", Version = "v1"
});
options.DocInclusionPredicate((docName, description) => true);
options.CustomSchemaIds(type => type.FullName);
});
......
// 添加内部服务的Swagger终点
app.UseSwaggerUIWithYarp();
//访问网关地址,自动跳转到 /swagger 的首页
app.UseRewriter(new RewriteOptions()
// Regex for "", "/" and "" (whitespace)
.AddRedirect("^(|\\|\\s+)$", "/swagger"));
app.UseRouting();
其中,调用方法 app.UseSwaggerUIWithYarp(); 的目的是:添加内部服务的Swagger终点,其代码如下:
代码清单:YarpGateway/Extensions/YarpSwaggerUIBuilderExtensions.cs
using Yarp.ReverseProxy.Configuration;
namespace YarpGateway.Extensions;
public static class YarpSwaggerUIBuilderExtensions
{
public static IApplicationBuilder UseSwaggerUIWithYarp(this IApplicationBuilder app)
{
var serviceProvider = app.ApplicationServices;
app.UseSwagger();
app.UseSwaggerUI(options =>
{
var configuration = serviceProvider.GetRequiredService<IConfiguration>();
var logger = serviceProvider.GetRequiredService<ILogger<Program>>();
var proxyConfigProvider = serviceProvider.GetRequiredService<IProxyConfigProvider>();
var yarpConfig = proxyConfigProvider.GetConfig();
var routedClusters = yarpConfig.Clusters
.SelectMany(t => t.Destinations,
(clusterId, destination) => new { clusterId.ClusterId, destination.Value });
var groupedClusters = routedClusters
.GroupBy(q => q.Value.Address)
.Select(t => t.First())
.Distinct()
.ToList();
foreach (var clusterGroup in groupedClusters)
{
var routeConfig = yarpConfig.Routes.FirstOrDefault(q =>
q.ClusterId == clusterGroup.ClusterId);
if (routeConfig == null)
{
logger.LogWarning($"Swagger UI: Couldn't find route configuration for {clusterGroup.ClusterId}...");
continue;
}
options.SwaggerEndpoint($"{clusterGroup.Value.Address}/swagger/v1/swagger.json", $"{routeConfig.RouteId} API");
options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]);
}
});
return app;
}
}
关键代码:
options.SwaggerEndpoint($"{clusterGroup.Value.Address}/swagger/v1/swagger.json", $"{routeConfig.RouteId} API");
通过 IProxyConfigProvider 得到内部服务的信息,如下图所示:
然后,拼接出内部服务的 Swagger 信息地址,
$"{clusterGroup.Value.Address}/swagger/v1/swagger.json"
最终得到两个服务的Swagger信息地址:
- IdentityServer 的 Swagger 信息地址:
http://localhost:7711/swagger/v1/swagger.json
- OrderService 的 Swagger 信息地址:
http://localhost:7721/swagger/v1/swagger.json
最后,根据信息添加Swagger终点:
options.SwaggerEndpoint(
$"{clusterGroup.Value.Address}/swagger/v1/swagger.json",
$"{routeConfig.RouteId} API"
);
其中,
routeConfig.RouteId
: Identity Service 或 Ordering Service
访问网关 Swagger
访问网地址:http://localhost:7700
自动跳转到地址:http://localhost:7700/swagger/index.html
右上角有个下拉框,可以选择不同的服务的Swagger,这里切换到 OrderService 的Swagger,如下图所示:
在网关 Swagger 调用服务接口
可以在网关 Swagger 调用内部服务接口,如下图所示:
返回:
标签:网关,Swagger,app,Yarp,json,swagger,options 来源: https://www.cnblogs.com/easy5weikai/p/16314830.html