上一篇我们基础服务初步搭建完毕,接下来我们整一下认证和网关。

搭建认证服务

认证服务的话,ABP CLI生成的所有模板都包括了一个AuthServer。我们直接生成模板然后微调一下就可以直接用了。

abp new FunShow -t app --tiered

使用命令创建模板后,我们可以找到一个AuthServer。把项目移动到Apps目录下,然后我们开始改造一下这个项目。
首先修改项目文件的引用配置
修改EFCore项目引用为AdministrationService.EntityFrameworkCore和IdentityService.EntityFrameworkCore,
然后添加Shared.Localization和Shared.Hosting.AspNetCore项目引用,别的基本不用怎么修改,完整项目配置为:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <Import Project="..\..\..\..\common.props" />

  <PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<UserSecretsId>b83bc18b-a6ca-4e2d-a827-26ffaff35dce</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\..\..\..</DockerfileContext>
</PropertyGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="6.0.5" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
</ItemGroup> <ItemGroup>
<PackageReference Include="Volo.Abp.Caching.StackExchangeRedis" Version="7.0.0" />
<PackageReference Include="Volo.Abp.EventBus.RabbitMQ" Version="7.0.0" />
<PackageReference Include="Volo.Abp.BackgroundJobs.RabbitMQ" Version="7.0.0" />
<PackageReference Include="Volo.Abp.Account.Web.OpenIddict" Version="7.0.0" />
<PackageReference Include="Volo.Abp.Account.Application" Version="7.0.0" />
<PackageReference Include="Volo.Abp.Account.HttpApi" Version="7.0.0" />
</ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\services\administration\src\FunShow.AdministrationService.EntityFrameworkCore\FunShow.AdministrationService.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\..\..\services\identity\src\FunShow.IdentityService.EntityFrameworkCore\FunShow.IdentityService.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\..\..\shared\FunShow.Shared.Hosting.AspNetCore\FunShow.Shared.Hosting.AspNetCore.csproj" />
<ProjectReference Include="..\..\..\..\shared\FunShow.Shared.Localization\FunShow.Shared.Localization.csproj" />
</ItemGroup> <ItemGroup>
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
</ItemGroup> <ItemGroup>
<Compile Remove="Logs\**" />
<Content Remove="Logs\**" />
<EmbeddedResource Remove="Logs\**" />
<None Remove="Logs\**" />
</ItemGroup> </Project>

然后修改Program文件,主要是日志配置修改一下,别的不用改动

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using FunShow.Shared.Hosting.AspNetCore;
using Serilog; namespace FunShow.AuthServer; public class Program
{
public async static Task<int> Main(string[] args)
{
var assemblyName = typeof(Program).Assembly.GetName().Name; SerilogConfigurationHelper.Configure(assemblyName); try
{
Log.Information($"Starting {assemblyName}.");
var builder = WebApplication.CreateBuilder(args);
builder.Host
.AddAppSettingsSecretsJson()
.UseAutofac()
.UseSerilog();
await builder.AddApplicationAsync<FunShowAuthServerModule>();
var app = builder.Build();
await app.InitializeApplicationAsync();
await app.RunAsync();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, $"{assemblyName} terminated unexpectedly!");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
}

修改module.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using FunShow.AdministrationService.EntityFrameworkCore;
using FunShow.IdentityService.EntityFrameworkCore;
using FunShow.Shared.Hosting.AspNetCore;
using Prometheus;
using StackExchange.Redis;
using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.Account.Web;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.Auditing;
using Volo.Abp.BackgroundJobs.RabbitMQ;
using Volo.Abp.Caching;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.Emailing;
using Volo.Abp.EventBus.RabbitMq;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.OpenIddict;
using Volo.Abp.UI.Navigation.Urls;
using Volo.Abp.VirtualFileSystem;
using Microsoft.AspNetCore.HttpOverrides;
using FunShow.Shared.Localization; namespace FunShow.AuthServer; [DependsOn(
typeof(AbpCachingStackExchangeRedisModule),
typeof(AbpEventBusRabbitMqModule),
typeof(AbpBackgroundJobsRabbitMqModule),
typeof(AbpAspNetCoreMvcUiLeptonXLiteThemeModule),
typeof(AbpAccountWebOpenIddictModule),
typeof(AbpAccountApplicationModule),
typeof(AbpAccountHttpApiModule),
typeof(AdministrationServiceEntityFrameworkCoreModule),
typeof(IdentityServiceEntityFrameworkCoreModule),
typeof(FunShowSharedHostingAspNetCoreModule),
typeof(FunShowSharedLocalizationModule)
)]
public class FunShowAuthServerModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration(); PreConfigure<OpenIddictBuilder>(builder =>
{
builder.AddValidation(options =>
{
options.AddAudiences("AccountService");
options.UseLocalServer();
options.UseAspNetCore();
});
});
if (!hostingEnvironment.IsDevelopment())
{
PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
{
options.AddDevelopmentEncryptionAndSigningCertificate = false;
}); PreConfigure<OpenIddictServerBuilder>(builder =>
{
builder.AddSigningCertificate(GetSigningCertificate(hostingEnvironment, configuration));
builder.AddEncryptionCertificate(GetSigningCertificate(hostingEnvironment, configuration));
});
}
} public override void ConfigureServices(ServiceConfigurationContext context)
{
//You can disable this setting in production to avoid any potential security risks.
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true; var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration(); ConfigureBundles();
ConfigureSwagger(context, configuration);
ConfigureSameSiteCookiePolicy(context);
ConfigureExternalProviders(context); Configure<AbpMultiTenancyOptions>(options =>
{
options.IsEnabled = true;
}); Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "AuthServer";
}); Configure<AppUrlOptions>(options =>
{
options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"].Split(','));
}); Configure<AbpDistributedCacheOptions>(options =>
{
options.KeyPrefix = "FunShow:";
}); var dataProtectionBuilder = context.Services.AddDataProtection().SetApplicationName("FunShow");
var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
dataProtectionBuilder.PersistKeysToStackExchangeRedis(redis, "FunShow-Protection-Keys"); context.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder
.WithOrigins(
configuration["App:CorsOrigins"]
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.Trim().RemovePostFix("/"))
.ToArray()
)
.WithAbpExposedHeaders()
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
}); #if DEBUG
context.Services.Replace(ServiceDescriptor.Singleton<IEmailSender, NullEmailSender>());
#endif if (hostingEnvironment.IsDevelopment())
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.ReplaceEmbeddedByPhysical<FunShowSharedLocalizationModule>(Path.Combine(
hostingEnvironment.ContentRootPath,
$"..{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}shared{Path.DirectorySeparatorChar}FunShow.Shared.Localization"));
});
}
} public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment(); var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>(); if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseAbpRequestLocalization(); if (!env.IsDevelopment())
{
app.UseErrorPage();
}
var forwardOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
RequireHeaderSymmetry = false
}; forwardOptions.KnownNetworks.Clear();
forwardOptions.KnownProxies.Clear(); // ref: https://github.com/aspnet/Docs/issues/2384
app.UseForwardedHeaders(forwardOptions); app.UseCorrelationId();
app.UseAbpSecurityHeaders();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseCookiePolicy();
app.UseHttpMetrics();
app.UseAuthentication();
app.UseAbpOpenIddictValidation();
app.UseAbpSerilogEnrichers();
app.UseUnitOfWork();
app.UseAuthorization();
app.UseSwagger();
app.UseAbpSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Account Service API");
options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
});
app.UseAuditing();
app.UseConfiguredEndpoints(endpoints =>
{
endpoints.MapMetrics();
});
} private void ConfigureBundles()
{
Configure<AbpBundlingOptions>(options =>
{
options.StyleBundles.Configure(
LeptonXLiteThemeBundles.Styles.Global,
bundle =>
{
bundle.AddFiles("/global-styles.css");
}
);
});
} private void ConfigureExternalProviders(ServiceConfigurationContext context)
{
context.Services.AddAuthentication();
} private X509Certificate2 GetSigningCertificate(IWebHostEnvironment hostingEnv, IConfiguration configuration)
{
var fileName = "authserver.pfx";
var passPhrase = "2D7AA457-5D33-48D6-936F-C48E5EF468ED";
var file = Path.Combine(hostingEnv.ContentRootPath, fileName); if (!File.Exists(file))
{
throw new FileNotFoundException($"Signing Certificate couldn't found: {file}");
} return new X509Certificate2(file, passPhrase);
} private void ConfigureSwagger(ServiceConfigurationContext context, IConfiguration configuration)
{
SwaggerConfigurationHelper.ConfigureWithAuth(
context: context,
authority: configuration["AuthServer:Authority"],
scopes: new Dictionary<string, string> {
/* Requested scopes for authorization code request and descriptions for swagger UI only */
{ "AccountService", "Account Service API" }
},
apiTitle: "Account Service API"
);
} private void ConfigureSameSiteCookiePolicy(ServiceConfigurationContext context)
{
context.Services.AddSameSiteCookiePolicy();
}
}

最后修改配置文件

{
"App": {
"SelfUrl": "https://localhost:44322",
"CorsOrigins": "http://localhost:4200,http://localhost:9527,https://localhost:44307,https://localhost:44325,https://localhost:44353,https://localhost:44367,https://localhost:44388,https://localhost:44381,https://localhost:44361",
"RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307,https://localhost:44321,http://localhost:9527"
},
"AuthServer": {
"Authority": "https://localhost:44322",
"RequireHttpsMetadata": "true",
"SwaggerClientId": "WebGateway_Swagger"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"AdministrationService": "Host=localhost;Port=5432;User ID=postgres;password=myPassw0rd;Pooling=true;Database=FunShow_Administration;",
"IdentityService": "Host=localhost;Port=5432;User ID=postgres;password=myPassw0rd;Pooling=true;Database=FunShow_Identity;"
},
"StringEncryption": {
"DefaultPassPhrase": "fCrJICTG3WoyissG"
},
"Redis": {
"Configuration": "localhost:6379"
},
"RabbitMQ": {
"Connections": {
"Default": {
"HostName": "localhost"
}
},
"EventBus": {
"ClientName": "FunShow_AuthServer",
"ExchangeName": "FunShow"
}
},
"ElasticSearch": {
"Url": "http://localhost:9200"
}
}

这样我们认证服务即修改完成。

搭建网关服务

网关服务我们直接新建一个空asp.net core项目。
然后只需要添加一个我们的Shared.Hosting.Gateways项目引用即可。

<Project Sdk="Microsoft.NET.Sdk.Web">

  <Import Project="..\..\..\..\common.props" />

  <PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\shared\FunShow.Shared.Hosting.Gateways\FunShow.Shared.Hosting.Gateways.csproj" />
</ItemGroup> <ItemGroup>
<Compile Remove="Logs\**" />
<Content Remove="Logs\**" />
<EmbeddedResource Remove="Logs\**" />
<None Remove="Logs\**" />
</ItemGroup> </Project>

修改Program.cs

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using FunShow.Shared.Hosting.AspNetCore;
using Serilog; namespace FunShow.WebGateway; public class Program
{
public async static Task<int> Main(string[] args)
{
var assemblyName = typeof(Program).Assembly.GetName().Name; SerilogConfigurationHelper.Configure(assemblyName); try
{
Log.Information($"Starting {assemblyName}.");
var builder = WebApplication.CreateBuilder(args);
builder.Host
.AddAppSettingsSecretsJson()
.AddYarpJson()
.UseAutofac()
.UseSerilog();
await builder.AddApplicationAsync<FunShowWebGatewayModule>();
var app = builder.Build();
await app.InitializeApplicationAsync();
await app.RunAsync();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, $"{assemblyName} terminated unexpectedly!");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
}

这里和认证服务基本一致,就是多了一个AddYarpJson()来添加我们的yarp的配置文件。
在目录下新建yarp.json文件,添加我们的yarp配置内容。配置集群和路由如下:

{
"ReverseProxy": {
"Routes": {
"Account Service": {
"ClusterId": "accountCluster",
"Match": {
"Path": "/api/account/{**everything}"
}
},
"Identity Service": {
"ClusterId": "identityCluster",
"Match": {
"Path": "/api/identity/{**everything}"
}
},
"Administration Service": {
"ClusterId": "administrationCluster",
"Match": {
"Path": "/api/abp/{**everything}"
}
},
"Logging Service": {
"ClusterId": "loggingCluster",
"Match": {
"Path": "/api/LoggingService/{**everything}"
}
},
"feature-management-route": {
"ClusterId": "feature-management-cluster",
"Match": {
"Path": "/api/feature-management/{**everything}"
}
},
"permission-management-route": {
"ClusterId": "permission-management-cluster",
"Match": {
"Path": "/api/permission-management/{**everything}"
}
},
"setting-management-route": {
"ClusterId": "setting-management-cluster",
"Match": {
"Path": "/api/setting-management/{**everything}"
}
}
},
"Clusters": {
"accountCluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:44322"
}
}
},
"identityCluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:44388"
}
}
},
"administrationCluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:44367"
}
}
},
"loggingCluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:45124"
}
}
},
"feature-management-cluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:44367"
}
}
},
"permission-management-cluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:44367"
}
}
},
"setting-management-cluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:44367"
}
}
}
}
}
}

在appsettings.json文件添加我们认证服务的地址

{
"App": {
"SelfUrl": "https://localhost:44325",
"CorsOrigins": "http://localhost:4200,https://localhost:44307,http://localhost:9527"
},
"AuthServer": {
"Authority": "https://localhost:44322",
"RequireHttpsMetadata": "true",
"SwaggerClientId": "WebGateway_Swagger"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Redis": {
"Configuration": "localhost:6379"
},
"ElasticSearch": {
"Url": "http://localhost:9200"
}
}

最后我们添加FunShowWebGatewayModule文件。配置我们yarp的服务。

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Rewrite;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using FunShow.Shared.Hosting.AspNetCore;
using FunShow.Shared.Hosting.Gateways;
using Volo.Abp;
using Volo.Abp.Modularity; namespace FunShow.WebGateway; [DependsOn(
typeof(FunShowSharedHostingGatewaysModule)
)]
public class FunShowWebGatewayModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Enable if you need hosting environment
// var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
var hostingEnvironment = context.Services.GetHostingEnvironment(); SwaggerConfigurationHelper.ConfigureWithAuth(
context: context,
authority: configuration["AuthServer:Authority"],
scopes: new
Dictionary<string, string> /* Requested scopes for authorization code request and descriptions for swagger UI only */ {
{ "AccountService", "Account Service API" },
{ "IdentityService", "Identity Service API" },
{ "AdministrationService", "Administration Service API" },
{ "LoggingService", "Logging Service API" }
},
apiTitle: "Web Gateway API"
); context.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder
.WithOrigins(
configuration["App:CorsOrigins"]
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.Trim().RemovePostFix("/"))
.ToArray()
)
.WithAbpExposedHeaders()
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
} public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment(); if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCorrelationId();
app.UseAbpSerilogEnrichers();
app.UseCors();
app.UseSwaggerUIWithYarp(context); app.UseRewriter(new RewriteOptions()
// Regex for "", "/" and "" (whitespace)
.AddRedirect("^(|\\|\\s+)$", "/swagger")); app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapReverseProxy();
});
}
}

UseSwaggerUIWithYarp是从我们Yarp配置文件中读取服务信息去构造swagger路由配置。
好了,到这我们认证服务和网关服务也搭建完毕,下一篇我们开始迁移数据库。

ABP微服务系列学习-搭建自己的微服务结构(三)的更多相关文章

  1. springcloud微服务架构搭建

    SpringCloud微服务框架搭建 一.微服务架构 1.1什么是分布式 不同模块部署在不同服务器上 作用:分布式解决网站高并发带来问题 1.2什么是集群 多台服务器部署相同应用构成一个集群 作用:通 ...

  2. SprngCloud微服务框架搭建(一)

    参照来源 :https://blog.csdn.net/forezp/article/details/70148833 1.简介 目前来说,SpringCloud是比较完整的微服务解决方案框架.不像其 ...

  3. Spring Cloud 微服务中搭建 OAuth2.0 认证授权服务

    在使用 Spring Cloud 体系来构建微服务的过程中,用户请求是通过网关(ZUUL 或 Spring APIGateway)以 HTTP 协议来传输信息,API 网关将自己注册为 Eureka ...

  4. 【spring colud】spring cloud微服务项目搭建【spring boot2.0】

    spring cloud微服务项目搭建 =================================== 示例版本: 1.spring boot 2.0版本 2.开发工具 IntellJ IDE ...

  5. 简单Spring Cloud 微服务框架搭建

    微服务是现在比较流行的技术,对于程序猿而言,了解并搭建一个基本的微服务框架是很有必要滴. 微服务包含的内容非常多,一般小伙伴们可以根据自己的需求不断添加各种组件.框架. 一般情况下,基本的微服务框架包 ...

  6. java架构之路-(微服务专题)初步认识微服务与nacos初步搭建

    历史演变: 以前我们都是一个war包,包含了很多很多的代码,反正我开始工作的时候做的就是这样的项目,一个金融系统,代码具体多少行记不清楚了,内部功能超多,但是实际能用到的不多,代码冗余超大,每次部署大 ...

  7. 十一、Docker搭建部署SpringCloud微服务项目Demo

    环境介绍 技术选型:SpringCloud&SpringCloud Alibaba&Docker 微服务模块划分: 员工模块:ems-employees 部门模块:ems-depart ...

  8. SpringCloudAlibaba 微服务讲解(二)微服务环境搭建

    微服务环境搭建 我们这次是使用的电商项目的商品.订单.用户为案例进行讲解 2.1 案例准备 2.1.1 技术选型 maven :3.3.9 数据库:mysql 持久层:SpringData JPA S ...

  9. (3)go-micro微服务项目搭建

    目录 一 微服务项目介绍 二 go-micro安装 1.拉取micro镜像 2.生成项目目录 三 项目搭建 使用DDD模式开发项目: 四 最后 一 微服务项目介绍 账户功能是每一个系统都绕不开的一部分 ...

  10. springCloud 微服务框架搭建入门(很简单的一个案例不喜勿扰)

    Spring cloud 实现服务注册及发现 服务注册与发现对于微服务系统来说非常重要.有了服务发现与注册,你就不需要整天改服务调用的配置文件了,你只需要使用服务的标识符,就可以访问到服务. clou ...

随机推荐

  1. 【每日一题】【回溯】【StringBuilder】2021年12月7日-17. 电话号码的字母组合

    给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合.答案可以按 任意顺序 返回. 给出数字到字母的映射如下(与电话按键相同).注意 1 不对应任何字母. 来源:力扣(LeetCode)链 ...

  2. selenium 之可视模式、静默模式、忽略证书不可用的设置

    1.可视模式的设置(在前台工作) from selenium import webdriver import time url = "https://y.qq.com/n/ryqq/song ...

  3. js 获取当前时间转换时间戳 (毫秒)

    js 当前时间转换毫秒数 五种方式   var date = new Date().getTime(); var date = new Date().valueOf(); var date = +ne ...

  4. CH9434-MCU代码移植,芯片使用详细说明(附Linux开发资料链接)

    简介 CH9434是一款SPI转四串口转接芯片,提供四组全双工的9线异步串口,用于单片机/嵌入式/安卓系统扩展异步串口.提供25路GPIO,以及支持RS485收发控制引脚TNOW.本篇基于STM32F ...

  5. Android 使用实现简单的音乐播放以及管理

    这里主要通过 MediaPlayer以及 AudioManager 来实现的对应的功能. 1.第一种,播放本地媒体文件: 你需要自己准备一个MP3格式的音频文件: 然后在资源目录(res)里面新建一个 ...

  6. 孤独的照片【USACO 2021 December Contest Bronze】

    孤独的照片 Farmer John 最近购入了 \(N\) 头新的奶牛,每头奶牛的品种是更赛牛(Guernsey)或荷斯坦牛(Holstein)之一. 奶牛目前排成一排,Farmer John 想要为 ...

  7. windows使用管理员权限安装软件

    安装步骤 系统搜索 cmd 点击右键,使用管理者方式运行 输入用户名密码 成功以管理员身份运行 cd 到软件存储的目录 输入软件执行文件名, 按回车键,成功开始安装

  8. 音频编辑服务UI SDK接入指导及常见问题

    华为 HMS Core 音频编辑服务(Audio Editor Kit)是华为帮助全球开发者快速构建各类应用音频能力的服务,汇聚了华为在音乐.语音等相关音频领域的先进技术.音频编辑服务为开发者们提供音 ...

  9. Blazor嵌套传递

    实现创建一个Blazor Server空的应用程序 创建一个Tab.razor 并且添加以下代码 <div> @Title </div> @code { [CascadingP ...

  10. TCP与UDP、socket模块

    1.传输层之TCP与UDP协议 1.TCP协议 1.传输控制协议(也称为TCP协议或可靠协议)是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议,(数据不容易丢失);造成数据不容 ...