.NETCore微服务探寻(一) - 网关
前言
一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目。正好由于最近刚好辞职,有了时间可以写写自己感兴趣的东西,所以在此想把自己了解的微服务相关的概念和技术框架使用实现记录在一个完整的工程中,由于本人技术有限,所以错误的地方希望大家指出。\
什么是Api网关
由于微服务把具体的业务分割成单独的服务,所以如果直接将每个服务都与调用者直接,那么维护起来将相当麻烦与头疼,Api网关担任的角色就是整合请求并按照路由规则转发至服务的实例,并且由于所有所有请求都经过网关,那么网关还可以承担一系列宏观的拦截功能,例如安全认证,日志,熔断
为什么需要Api网关
因为Api网关可以提供安全认证,日志,熔断相关的宏观拦截的功能,也可以屏蔽多个下游服务的内部细节
有哪些有名的Api网关项目
- Zuul Spring Cloud 集成
- Kong 一款lua轻量级网关项目
- Ocelot .NETCore网关项目
Ocelot使用
1.通过Nuget安装Ocelot
2.准备并编辑Ocelot配置信息
Ocelot.json
{
"ReRoutes": [
// Auth
{
"UpstreamPathTemplate": "/auth/{action}", // 上游请求路径模板
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ], // 上游请求方法
"ServiceName": "Auth", // 服务名称
"UseServiceDiscovery": true, // 是否使用服务发现
"DownstreamPathTemplate": "/connect/{action}", // 下游匹配路径模板
"DownstreamScheme": "http", // 下游请求
"LoadBalancerOptions": { // 负载均衡配置
"Type": "RoundRobin"
}
//,
// 如果不采用服务发现需要指定下游host
//"DownstreamHostAndPorts": [
// {
// "Host": "10.0.1.10",
// "Port": 5000
// },
// {
// "Host": "10.0.1.11",
// "Port": 5000
// }
//]
}
],
"GlobalConfiguration": { // 全局配置信息
"BaseUrl": "http://localhost:5000", // 请求 baseurl
"ServiceDiscoveryProvider": { //服务发现提供者
"Host": "106.53.199.185",
"Port": 8500,
"Type": "Consul" // 使用Consul
}
}
}
3.添加Ocelot json文件到项目中
将Config目录下的ocelot.json添加到项目中
4.在网关项目中 StartUp ConfigService中添加Ocelot的服务,在Configure中添加Ocelot的中间件(由于我这里使用了Consul作为服务发现,所以需要添加Consul的依赖的服务AddConsul,如果不需要服务发现的话可以不用添加)
5.将需要发现的服务通过代码在启动时注册到Consul中
我这里自己封装了一个注册服务的扩展(写的比较随意没有在意细节)
appsettings.json 中添加注册服务配置信息
"ServiceOptions": {
"ServiceIP": "localhost",
"ServiceName": "Auth",
"Port": 5800,
"HealthCheckUrl": "/api/health",
"ConsulOptions": {
"Scheme": "http",
"ConsulIP": "localhost",
"Port": 8500
}
}
扩展代码 ConsulExtensions(注意:3.1中 IApplicationLifetime已废弃 所以使用的是IHostApplicationLifetime 作为程序生命周期注入的方式)
using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
namespace ForDotNet.Common.Consul.Extensions
{
/// <summary>
/// 服务配置信息
/// </summary>
public class ServiceOptions
{
/// <summary>
/// 服务ip
/// </summary>
public string ServiceIP { get; set; }
/// <summary>
/// 服务名称
/// </summary>
public string ServiceName { get; set; }
/// <summary>
/// 协议类型http or https
/// </summary>
public string Scheme { get; set; } = "http";
/// <summary>
/// 端口
/// </summary>
public int Port { get; set; }
/// <summary>
/// 健康检查接口
/// </summary>
public string HealthCheckUrl { get; set; } = "/api/values";
/// <summary>
/// 健康检查间隔时间
/// </summary>
public int HealthCheckIntervalSecond { get; set; } = 10;
/// <summary>
/// consul配置信息
/// </summary>
public ConsulOptions ConsulOptions { get; set; }
}
/// <summary>
/// consul配置信息
/// </summary>
public class ConsulOptions
{
/// <summary>
/// consul ip
/// </summary>
public string ConsulIP { get; set; }
/// <summary>
/// consul 端口
/// </summary>
public int Port { get; set; }
/// <summary>
/// 协议类型http or https
/// </summary>
public string Scheme { get; set; } = "http";
}
/// <summary>
/// consul注册客户端信息
/// </summary>
public class ConsulClientInfo
{
/// <summary>
/// 注册信息
/// </summary>
public AgentServiceRegistration RegisterInfo { get; set; }
/// <summary>
/// consul客户端
/// </summary>
public ConsulClient Client { get; set; }
}
/// <summary>
/// consul扩展(通过配置文件配置)
/// </summary>
public static class ConsulExtensions
{
private static readonly ServiceOptions serviceOptions = new ServiceOptions();
/// <summary>
/// 添加consul
/// </summary>
public static void AddConsulServiceDiscovery(this IServiceCollection services)
{
var config = services.BuildServiceProvider().GetService<IConfiguration>();
config.GetSection("ServiceOptions").Bind(serviceOptions);
//config.Bind(serviceOptions);
if (serviceOptions == null)
{
throw new Exception("获取服务注册信息失败!请检查配置信息是否正确!");
}
Register(services);
}
/// <summary>
/// 添加consul(通过配置opt对象配置)
/// </summary>
/// <param name="app"></param>
/// <param name="life">引用生命周期</param>
/// <param name="options">配置参数</param>
public static void AddConsulServiceDiscovery(this IServiceCollection services, Action<ServiceOptions> options)
{
options.Invoke(serviceOptions);
Register(services);
}
/// <summary>
/// 注册consul服务发现
/// </summary>
/// <param name="app"></param>
/// <param name="life"></param>
public static void UseConsulServiceDiscovery(this IApplicationBuilder app, IHostApplicationLifetime life)
{
var consulClientInfo = app.ApplicationServices.GetRequiredService<ConsulClientInfo>();
if (consulClientInfo != null)
{
life.ApplicationStarted.Register( () =>
{
consulClientInfo.Client.Agent.ServiceRegister(consulClientInfo.RegisterInfo).Wait();
});
life.ApplicationStopping.Register( () =>
{
consulClientInfo.Client.Agent.ServiceDeregister(consulClientInfo.RegisterInfo.ID).Wait();
});
}
else
{
throw new NullReferenceException("未找到相关consul客户端信息!");
}
}
private static void Register(this IServiceCollection services)
{
if (serviceOptions == null)
{
throw new Exception("获取服务注册信息失败!请检查配置信息是否正确!");
}
if (serviceOptions.ConsulOptions == null)
{
throw new ArgumentNullException("请检查是否配置Consul信息!");
}
string consulAddress = $"{serviceOptions.ConsulOptions.Scheme}://{serviceOptions.ConsulOptions.ConsulIP}:{serviceOptions.ConsulOptions.Port}";
var consulClient = new ConsulClient(opt =>
{
opt.Address = new Uri(consulAddress);
});
var httpCheck = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(10), // 服务启动多久后注册
Interval = TimeSpan.FromSeconds(serviceOptions.HealthCheckIntervalSecond), // 间隔
HTTP = $"{serviceOptions.Scheme}://{serviceOptions.ServiceIP}:{serviceOptions.Port}{serviceOptions.HealthCheckUrl}",
Timeout = TimeSpan.FromSeconds(10)
};
var registration = new AgentServiceRegistration()
{
Checks = new[] { httpCheck },
ID = Guid.NewGuid().ToString(),
Name = serviceOptions.ServiceName,
Address = serviceOptions.ServiceIP,
Port = serviceOptions.Port,
};
services.AddSingleton(new ConsulClientInfo()
{
Client = consulClient,
RegisterInfo = registration
});
}
}
}
6.启动运行
- 启动consul
- 启动 Auth,Gateway项目
- 通过网关项目访问Auth
启动Consul
为了方便演示这里是以开发者启动的consul
在consul.exe的目录下执行
consul agent -dev -ui // 开发者模式运行带ui
启动 Auth,Gateway项目
启动项目和可以发现我的们Auth服务已经注册进来了
通过网关访问Auth
我们这里访问 http://localhost:5000/auth/token 获取token
我们可以看到网关项目接收到了请求并在控制台中打印出以下信息
然后在Auth项目中的控制台中可以看到已经成功接收到了请求并响应
.NETCore微服务探寻(一) - 网关的更多相关文章
- .NETCore微服务探寻(三) - 分布式日志
前言 一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目 ...
- .NETCore微服务探寻(二) - 认证与授权
前言 一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目 ...
- .NETCore微服务探寻(三) - 远程过程调用(RPC)
前言 一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目 ...
- AspNetCore微服务下的网关-Kong(一)
Kong是Mashape开源的高性能高可用API网关和API服务管理层.它基于OpenResty,进行API管理,并提供了插件实现API的AOP.Kong在Mashape 管理了超过15,000 个A ...
- (1)学习笔记 ) ASP.NET CORE微服务 Micro-Service ---- 什么是微服务架构,.netCore微服务选型
开发工具:VS2017 .Net Core 2.1 什么是微服务?单体结构: 缺点: 1)只能采用同一种技术,很难用不同的语言或者语言不同版本开发不同模块: 2)系统耦合性强,一旦其中一个模块有问题, ...
- (1).NET CORE微服务 Micro-Service ---- 什么是微服务架构,.netCore微服务选型
开发工具:VS2017 .Net Core 2.1 什么是微服务?单体结构: 缺点:1)只能采用同一种技术,很难用不同的语言或者语言不同版本开发不同模块:2)系统耦合性强,一旦其中一个模块有问题,整个 ...
- 什么是微服务架构,.netCore微服务选型
什么是微服务架构,.netCore微服务选型 https://www.cnblogs.com/uglyman/p/9182485.html 开发工具:VS2017 .Net Core 2.1 什么是微 ...
- .NetCore微服务Surging新手傻瓜式 入门教程 学习日志---先让程序跑起来(一)
原文:.NetCore微服务Surging新手傻瓜式 入门教程 学习日志---先让程序跑起来(一) 写下此文章只为了记录Surging微服务学习过程,并且分享给广大想学习surging的基友,方便广大 ...
- .NetCore微服务Surging新手傻瓜式 入门教程 学习日志---结构简介(二)
原文:.NetCore微服务Surging新手傻瓜式 入门教程 学习日志---结构简介(二) 先上项目解决方案图: 以上可以看出项目结构可以划分为4大块,1是surging的核心底层,2,3,4都可以 ...
随机推荐
- Spring Boot 教程(1) - HelloWorld
Spring Boot 教程 - HelloWorld 1. Spring Boot 的由来 大家都知道,Spring框架是Java生态中举足轻重的轻量型框架,帮助我们广大的大佬们进行Java开发.S ...
- 公众号使用微信sdk的正确姿势
当我们做微信登录授权,微信公众号的分享,微信的h5支付等等等等的时候难免会用到微信sdk,当我们用react或vue做的spa应用,直接引入后会发现,在按安卓上可以正常调试,而ios上一直报签名错误( ...
- 阿里云ECS封25端口导致wordpress无法发送邮件的解决
在有人评论你的文章,wordpress默认会尝试向博主发送邮件,而如果你用的是阿里云ECS,你会发现评论已经成功了,但是由于邮件发送失败会导致用户评论后页面就卡住了,原因就在于阿里云的ECS目前已经全 ...
- [C#] [VS] Snippets快捷代码块之 Region
代码长了,阅读起来不方便, 于是,C#中我们经常会用 region来折叠代码块. 在VS中,输入 #region , 点Tab,会自动生成如下: #region MyRegion #endregion ...
- Android_四大组件之BroadcastReceiver
一.概述 BroadcastReceiver是广播接收器,接收来自 系统或应用发出的广播信息 并进行相应的逻辑处理. 自定义BroadcastReceiver只需继承android.content.B ...
- 创建执行线程方式三:实现Callable接口
Callable接口 ① Java 5.0 在 java.util.concurrent 提供了一个新的创建执行 线程的方式:Callable 接口② Callable 接口类似于 Runnable, ...
- 关于同一密码使用generate_password_hash生成不同的密码散列值
在python的 werkzeug.security 库中有两个函数generate_password_hash与check_password_hash用于对密码明文生成散列值以及检查密码是否与提供的 ...
- Azure AD(三)知识补充-Azure资源的托管标识
一,引言 来个惯例,吹水! 前一周因为考试,还有个人的私事,一下子差点颓废了.想了想,写博客这种的东西还是得坚持,再忙,也要检查.要养成一种习惯,同时这也是自我约束的一种形式.虽然说不能浪费大量时间在 ...
- jchdl - GSL实例 - ComplementOne(一的补码)
https://mp.weixin.qq.com/s/zZTnDdbCUCRGGpgpfAZsYQ 一的补码指对二进制数的每一位分别求补(二进制运算下0,1互为补数),实际运算即为对每一位取反.最 ...
- 折腾自己的js闭包(二)
前面我大致探讨了js里的闭包的相关概念,那么,到底在什么时候用它最好呢?存在即真理,只不过以前没发现它而已,先来看看下面的这几个用途吧 一.我首先想到的就是从函数外面访问它的内部变量,从而达到自己的一 ...