.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都可以 ...
随机推荐
- POJ3735
题目链接:http://poj.org/problem?id=3735 解题思路: 先构造一个(n+1)*(n+1)的单位矩阵E,在此基础上进行操作: 1.g i -------------& ...
- 基于 abp vNext 和 .NET Core 开发博客项目 - 异常处理和日志记录
在开始之前,我们实现一个之前的遗留问题,这个问题是有人在GitHub Issues(https://github.com/Meowv/Blog/issues/8)上提出来的,就是当我们对Swagger ...
- 简说Spring中的资源加载
声明: 本文若有 任何纰漏.错误,请不吝指正!谢谢! 问题描述 遇到一个关于资源加载的问题,因此简单的记录一下,对Spring资源加载也做一个记录. 问题起因是使用了@PropertySource来进 ...
- Spring_Bean的配置方式
1.通过工厂方法配置bean beans-factory.xml <?xml version="1.0" encoding="UTF-8"?> &l ...
- DataFrame-选择与切片
取得DataFrame对象reviews的description列的前10个值(或者说reviews前10行的description列): reviews.iloc[:10].loc[:,'descr ...
- 从 React 架构开始讲解 useState、useEffect 编程设计
随着前端开发复杂度增加,原生开发模式显得越来越笨重,前端框架也层出不穷. MVC 和 MVVM MVC MVC是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计 ...
- 利用Python网络爬虫采集天气网的实时信息—BeautifulSoup选择器
相信小伙伴们都知道今冬以来范围最广.持续时间最长.影响最重的一场低温雨雪冰冻天气过程正在进行中.预计,今天安徽.江苏.浙江.湖北.湖南等地有暴雪,局地大暴雪,新增积雪深度4-8厘米,局地可达10-20 ...
- sqlmap中文手册
Sqlmap中文手册 -Darren制作 零.前言 Sqlmap是十分著名的.自动化的SQL注入工具.为了较为系统地学习Sqlmap,我决定翻译一遍Sqlmap的用户手册,于是便有了此文.由于我英语 ...
- python数据类型 列表+元组
一:列表 二:元组 一:列表list: 1.列表中的每个元素都可变的,意味着可以对每个元素进行修改和删除: 2.列表是有序的,每个元素的位置是确定的,可以用索引去访问每个元素: 3.列表的所有元素放在 ...
- Bootstrap解决页面缩小变形的办法
bootstrap布局是应用得很广泛的一种网页布局方法,例如:我们用一种中间内容很流行的布局分布:3-6-3式布局.代码如下 <style type="text/css"&g ...