ABP微服务系列学习-搭建自己的微服务结构(三)
上一篇我们基础服务初步搭建完毕,接下来我们整一下认证和网关。
搭建认证服务
认证服务的话,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微服务系列学习-搭建自己的微服务结构(三)的更多相关文章
- springcloud微服务架构搭建
SpringCloud微服务框架搭建 一.微服务架构 1.1什么是分布式 不同模块部署在不同服务器上 作用:分布式解决网站高并发带来问题 1.2什么是集群 多台服务器部署相同应用构成一个集群 作用:通 ...
- SprngCloud微服务框架搭建(一)
参照来源 :https://blog.csdn.net/forezp/article/details/70148833 1.简介 目前来说,SpringCloud是比较完整的微服务解决方案框架.不像其 ...
- Spring Cloud 微服务中搭建 OAuth2.0 认证授权服务
在使用 Spring Cloud 体系来构建微服务的过程中,用户请求是通过网关(ZUUL 或 Spring APIGateway)以 HTTP 协议来传输信息,API 网关将自己注册为 Eureka ...
- 【spring colud】spring cloud微服务项目搭建【spring boot2.0】
spring cloud微服务项目搭建 =================================== 示例版本: 1.spring boot 2.0版本 2.开发工具 IntellJ IDE ...
- 简单Spring Cloud 微服务框架搭建
微服务是现在比较流行的技术,对于程序猿而言,了解并搭建一个基本的微服务框架是很有必要滴. 微服务包含的内容非常多,一般小伙伴们可以根据自己的需求不断添加各种组件.框架. 一般情况下,基本的微服务框架包 ...
- java架构之路-(微服务专题)初步认识微服务与nacos初步搭建
历史演变: 以前我们都是一个war包,包含了很多很多的代码,反正我开始工作的时候做的就是这样的项目,一个金融系统,代码具体多少行记不清楚了,内部功能超多,但是实际能用到的不多,代码冗余超大,每次部署大 ...
- 十一、Docker搭建部署SpringCloud微服务项目Demo
环境介绍 技术选型:SpringCloud&SpringCloud Alibaba&Docker 微服务模块划分: 员工模块:ems-employees 部门模块:ems-depart ...
- SpringCloudAlibaba 微服务讲解(二)微服务环境搭建
微服务环境搭建 我们这次是使用的电商项目的商品.订单.用户为案例进行讲解 2.1 案例准备 2.1.1 技术选型 maven :3.3.9 数据库:mysql 持久层:SpringData JPA S ...
- (3)go-micro微服务项目搭建
目录 一 微服务项目介绍 二 go-micro安装 1.拉取micro镜像 2.生成项目目录 三 项目搭建 使用DDD模式开发项目: 四 最后 一 微服务项目介绍 账户功能是每一个系统都绕不开的一部分 ...
- springCloud 微服务框架搭建入门(很简单的一个案例不喜勿扰)
Spring cloud 实现服务注册及发现 服务注册与发现对于微服务系统来说非常重要.有了服务发现与注册,你就不需要整天改服务调用的配置文件了,你只需要使用服务的标识符,就可以访问到服务. clou ...
随机推荐
- 12V转5V降压芯片,12V转3.3V稳压芯片电路图
12V转5V应用中,大多要求会输出电流高的,稳压LDO就不能满足了,需要使用DC-DC降压芯片来持续稳压5V,输出电流1000MA,2000MA,3000MA,5000MA等.不同的输出电流可以选择适 ...
- Leanote蚂蚁笔记-私人云笔记服务器搭建
title: Leanote蚂蚁笔记-私人云笔记服务器搭建 date: 2020-02-22 21:53:24 categories: - [IT,技术] - [IT,软件,程序] - [IT,软件, ...
- 使用Spring Reactor优化推荐流程
1. 背景 公司有一个推荐系统Rec,这个系统的主要功能是: 向外部系统提供推荐接口 根据请求获取推荐策略 根据推荐策略完成推荐的召回.过滤.打分.排序阶段 Rec作为微服务中的一环,本身不存储召回的 ...
- 个人电脑公网IPv6配置
一.前言 自己当时以低价买的阿里ECS云服务器马上要过期了,对于搭建个人博客.NAS这样服务器的需求购买ECS服务器成本太高了,刚好家里有台小型的桌面式笔记本,考虑用作服务器,但是公网IPv4的地址实 ...
- 边框 display属性 盒子模型 浮动 溢出 定位 z-index
目录 边框 隐藏属性 钓鱼网站 display visibility 盒子模型 调整方式 浮动 溢出 圆形头像的制作 定位 z-index属性 边框 /*border-left-width: 5px; ...
- Django 之swagger中尝试调试post请求时返回 "detail": "JSON parse error - Expecting value: line 1 column 1 (char)
swagger已配置OK,但发送POST请求时一直显示数据格式错误,怪异.... 经过各种查找资料,才发现setting.py文件中缺少配置 配置完成后重启服务,再次尝试发送POST请求,不会再报格式 ...
- Apache Kafka 移除 ZK Proposals
Zookeeper 和 KRaft 这里有一篇 Kafka 功能改进的 proposal 原文.要了解移除 ZK 的原因,可以仔细看看该文章.以下是对该文章的翻译. 动机 目前,Kafka 使用 Zo ...
- 由char和byte的关系引申出去——总结一下java中的字符编码相关知识
由char和byte的关系引申出去--总结一下java中的字符编码相关知识 一.字符编码 手持两把锟斤拷,口中直呼烫烫烫 在文章伊始,先来复习一下计算机中关于编码的一些基础知识,着重理清以下几 ...
- python之路50 ORM执行SQL语句 操作多表查询 双下线方法
ORM执行查询SQL语句 有时候ORM的操作效率可能偏低 我们是可以自己编写SQL的 方式1: models.User.objects.raw('select * from app01_user;') ...
- DVWA靶场实战(一)——Brute Force
DVWA靶场实战(一) 一.Brute Force: 1.漏洞原理: Brute Force是暴力破解的意思,大致原理就是利用穷举法,穷举出所有可能的密码. 2.攻击方法: Burpsuite中的In ...