微服务网关从零搭建——创建测试api以及api自动注入consul

Posted nontracey

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微服务网关从零搭建——创建测试api以及api自动注入consul相关的知识,希望对你有一定的参考价值。

consul 开发环境简易处理

consul 下载地址 : https://www.consul.io/downloads.html

此处使用windows 64版本 

为方便使用在创建一个bat文件 命令如下:

cd C:UsersLenovoDesktop    
consul.exe agent -dev

第一行为进入桌面

第二行为 执行consul开发模式

运行后可在 localhost:8500 地址处看到consul 后台服务管理页面

搭建测试API

由于 使用了consul 最新nuget包 所以 在创建的时候需要使用 .netcore 2.1 

由于已经搭建了demo1 这里演示截图会是demo2 创建方式一样

创建一个core 2.1的API空项目

技术分享图片

 

创建一个BaseController 用来保存配置信息

技术分享图片
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

namespace DemoApi_I.Controllers
{
    public class BaseController : ControllerBase
    {
        public static Setting Config;
        public BaseController(IOptions<Setting> setting)
        {
            Config = setting.Value;
        }
    }
}
BaseController

再添加一个健康检查的控制器

技术分享图片
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

namespace DemoApi_II.Controllers
{
    [Route("api/[controller]")]
    public class HealthController : BaseController
    {
        public HealthController(IOptions<Setting> setting) : base(setting)
        {
        }

        // GET api/values
        [HttpGet]
        public string Get()
        {
            return "ok";
        }
    }
}
HealthController.cs

为了统一显示 可以更改默认values控制器为

技术分享图片
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

namespace DemoApi_II.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : BaseController
    {
        public ValuesController(IOptions<Setting> setting) : base(setting)
        {
        }
        // GET api/values
        [HttpGet]
        public string Get()
        {
            var aaa = Config.ServiceName;
            return "二号测试API";
        }
    }
}
ValuesController

 接下来 增加 一个配置类

技术分享图片
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DemoApi_II
{
    public class Setting
    {
        /// <summary>
        /// 端口号
        /// </summary>
        public int Port { get; set; }
        /// <summary>
        /// 服务名称
        /// </summary>
        public string ServiceName { get; set; }
        /// <summary>
        /// 服务发现IP
        /// </summary>
        public string ConsulIP { get; set; }
        /// <summary>
        /// 服务发现端口号
        /// </summary>
        public int ConsulPort { get; set; }

    }
}
Setting.cs

在appsettings.json 内新增节点 

测试地址中只需要改端口号和服务名称即可 会自动读取本机ip到注入到consul中

技术分享图片
 "Setting": {
    "Port": "1001",
    "ServiceName": "demoAPi",
    "ConsulIP": "localhost",
    "ConsulPort": "8500"
  }
新增部分

注意 需要修改为 始终复制或者较新复制

技术分享图片

 

修改 Program.cs

技术分享图片
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace DemoApi_II
{
    public class Program
    {
        public static string StartPort;
        public static void Main(string[] args)
        {
            var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true)
.Build();
            StartPort = config.GetSection("Setting")["Port"];
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
              .UseUrls($"http://*:{StartPort}")
                .UseStartup<Startup>();
    }
}
Program.cs

修改startup.cs

技术分享图片
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ConsulRegisterHelper;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace DemoApi_II
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<Setting>(Configuration.GetSection("Setting"));
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseMvc();
            app.RegisterConsul(lifetime, new ServiceEntity
            {
                IP = NetworkHelper.LocalIPAddress,
                Port = Convert.ToInt32(Configuration.GetSection("Setting")["Port"]),
                ServiceName = Configuration.GetSection("Setting")["ServiceName"],
                ConsulIP = Configuration.GetSection("Setting")["ConsulIP"],
                ConsulPort = Convert.ToInt32(Configuration.GetSection("Setting")["ConsulPort"])
            });
        }
    }
}
Startup.cs

创建自动注入consul服务的类库

新建core2.1类库项目 取名ConsulRegisterHelper

将以下3个类创建即可

技术分享图片
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

namespace ConsulRegisterHelper
{
    public class NetworkHelper
    {
        public static string LocalIPAddress
        {
            get
            {
                UnicastIPAddressInformation mostSuitableIp = null;
                var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();

                foreach (var network in networkInterfaces)
                {
                    if (network.OperationalStatus != OperationalStatus.Up)
                        continue;
                    var properties = network.GetIPProperties();
                    if (properties.GatewayAddresses.Count == 0)
                        continue;

                    foreach (var address in properties.UnicastAddresses)
                    {
                        if (address.Address.AddressFamily != AddressFamily.InterNetwork)
                            continue;
                        if (IPAddress.IsLoopback(address.Address))
                            continue;
                        return address.Address.ToString();
                    }
                }

                return mostSuitableIp != null
                    ? mostSuitableIp.Address.ToString()
                    : "";
            }
        }

        public static int GetRandomAvaliablePort(int minPort = 1024, int maxPort = 65535)
        {
            Random rand = new Random();
            while (true)
            {
                int port = rand.Next(minPort, maxPort);
                if (!IsPortInUsed(port))
                {
                    return port;
                }
            }
        }

        private static bool IsPortInUsed(int port)
        {
            IPGlobalProperties ipGlobalProps = IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] ipsTCP = ipGlobalProps.GetActiveTcpListeners();

            if (ipsTCP.Any(p => p.Port == port))
            {
                return true;
            }

            IPEndPoint[] ipsUDP = ipGlobalProps.GetActiveUdpListeners();
            if (ipsUDP.Any(p => p.Port == port))
            {
                return true;
            }

            TcpConnectionInformation[] tcpConnInfos = ipGlobalProps.GetActiveTcpConnections();
            if (tcpConnInfos.Any(conn => conn.LocalEndPoint.Port == port))
            {
                return true;
            }

            return false;
        }
    }
}
NetworkHelper.cs
技术分享图片
using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using System;

namespace ConsulRegisterHelper
{
    public static class AppBuilderExtensions
    {
        public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IApplicationLifetime lifetime, ServiceEntity serviceEntity)
        {
            var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}"));//请求注册的 Consul 地址
            var httpCheck = new AgentServiceCheck()
            {
                DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
                Interval = TimeSpan.FromSeconds(3),//健康检查时间间隔,或者称为心跳间隔
                HTTP = $"http://{serviceEntity.IP}:{serviceEntity.Port}{serviceEntity.HealthUrl}",//健康检查地址
                Timeout = TimeSpan.FromSeconds(3)
            };

            // Register service with consul
            var registration = new AgentServiceRegistration()
            {
                Checks = new[] { httpCheck },
                ID = Guid.NewGuid().ToString(),
                Name = serviceEntity.ServiceName,
                Address = serviceEntity.IP,
                Port = serviceEntity.Port,
                Tags = new[] { $"urlprefix-/{serviceEntity.ServiceName}" }//添加 urlprefix-/servicename 格式的 tag 标签,以便 Fabio 识别
            };

            consulClient.Agent.ServiceRegister(registration).Wait();//服务启动时注册,内部实现其实就是使用 Consul API 进行注册(HttpClient发起)
            lifetime.ApplicationStopping.Register(() =>
            {
                consulClient.Agent.ServiceDeregister(registration.ID).Wait();//服务停止时取消注册
            });

            return app;
        }
    }
}
Register.cs
技术分享图片
using System;
using System.Collections.Generic;
using System.Text;

namespace ConsulRegisterHelper
{
    public class ServiceEntity
    {
        public ServiceEntity()
        {
            HealthUrl = "/api/health";
        }
        /// <summary>
        /// 服务IP
        /// </summary>
        public string IP { get; set; }
        /// <summary>
        /// 服务端口号
        /// </summary>
        public int Port { get; set; }
        /// <summary>
        /// 服务名称
        /// </summary>
        public string ServiceName { get; set; }
        /// <summary>
        /// 服务发现地址
        /// </summary>
        public string ConsulIP { get; set; }
        /// <summary>
        /// 服务发现端口号
        /// </summary>
        public int ConsulPort { get; set; }
        /// <summary>
        /// 健康检查地址默认为/api/health
        /// </summary>
        public string HealthUrl { get; set; }
    }
}
ServiceEntity.cs

在需要注入的服务Startup.cs中通过如下代码注入:

技术分享图片

 

创建bat文件方便测试使用

技术分享图片
E:
cd E:ServerApiOcelotGetWayDemoApi_IIinDebug
etcoreapp2.1
dotnet DemoApi_II.dll
实例代码

 到此 测试demoapi 准备完成

 

以上是关于微服务网关从零搭建——创建测试api以及api自动注入consul的主要内容,如果未能解决你的问题,请参考以下文章

微服务之:从零搭建ocelot网关和consul集群

微服务开源API网关Fizz Gateway

springGateWay网关搭建

网关服务Kong、Konga搭建记录

新浪微博 API 网关的定制化开发之路

谈API网关的背景架构以及落地方案