zoukankan      html  css  js  c++  java
  • 服务与服务之间的调用

    服务与服务之间的调用,

    解决方案目前比较流行的有

    1:基于rpc,如微软推荐的:grpc,创建grpc服务后可以生成proco等文件

    1:什么是GRPC?
    gRPC是与语言无关的高性能远程过程调用(RPC)框架。谷歌开发的grpc技术框架,C#端由微软的员工来维护升级
    
    2: 使用GRPC有啥好处?
    合同优先的API开发,默认情况下使用协议缓冲区,允许使用与语言无关的实现。
    可用于多种语言的工具,以生成强类型的服务器和客户端。
    支持客户端,服务器和双向流呼叫。
    通过Protobuf二进制序列化减少网络使用。
    
    GRPC的主要优点是:
    GRPC是与语言无关的高性能远程过程调用(RPC)框架。
    现代,高性能,轻量级的RPC框架。
    效率至关重要的轻量级微服务。
    开发需要多种语言的多语言系统。
    需要处理流式请求或响应的点对点实时服务。
    
    3:啥时候使用和不建议使用GRPC?
    直播,聊天等不适合
    
    4:使用GRPC的步骤
    ***************下次整理写一个案例,目前网络上有很多可以参考,长时间不使用容易忘记**************
    这次决定还是不使用GRPC,虽然效率上高一些,还得再多搞一个服务和通用的配置出来,而且如果服务多配置文件也会比较多,
    配置上也感觉不是很喜欢,所以就使用比较传统的方案二

    2:网络请求的工具,如系统自带的 IHttpClientFactory(从.NetCore 2.1官方已经优化),不是HttpClient(缺点可以网络上查询)

    get请求

    get测试效果截图: 

    post请求

     post测试效果截图:

     调用的步骤为:服务07调用06的服务,本地测试为ip一致,但是端口不一致,模拟不同的服务之间的调用

    为啥要这样设计?
    1
    :首先将各个服务的host如:http://localhost:8081等等都写在appsetting配置文件中, 这样方便维护和修改,一处修改处处修改的效果,修改替换后也不需要构建镜像再发布,直接Docker重启即可。 2:获取配置信息:采用枚举+常量+静态类,清晰明了,使用时不用到处声明变量,避免多次申请内存空间,提升系统执行效率。 3:基于第二点,有枚举,选择调用哪一个服务时方便高效点出来, HttpFactoryClient网络请求为优化后的解决方案,不用担心之前的版本Tcp/ip资源不能及时释放,而导致无资源可调用,因为已经内置pool池化。

    code主要代码如下:

    using GDBS.Shared.Data;
    using GDBS.Shared.Data.Const;
    
    using Microsoft.AspNetCore.Http;
    
    using Newtonsoft.Json;
    
    using System;
    using System.Collections.Generic;
    using System.Net.Http;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace GDBS.Shared.ToolKits.Tool
    {
        /// <summary>
        /// 跨服务 WebApi部分帮助类 jason  待进一步完善
        /// </summary>
        public class HttpClientHelper
        {
    
            private static string GetHostStrByConst(PlatFormEnum optionEnum)
            {
                string gethost = string.Empty;
                switch (optionEnum)
                {
                    case PlatFormEnum.BridgeService:
                        gethost = PlatFormApiHostOptions.BridgeService;
                        break;
                    case PlatFormEnum.GdbsProjectService:
                        gethost = PlatFormApiHostOptions.GdbsProjectService;
                        break;
                    case PlatFormEnum.ReceAndSendMsgService:
                        gethost = PlatFormApiHostOptions.ReceAndSendMsgService;
                        break;
                    case PlatFormEnum.ProvincialLevelService:
                        gethost = PlatFormApiHostOptions.ProvincialLevelService;
                        break;
                    case PlatFormEnum.ThirdPartyService:
                        gethost = PlatFormApiHostOptions.ThirdPartyService;
                        break;
                    case PlatFormEnum.MonitoringService:
                        gethost = PlatFormApiHostOptions.MonitoringService;
                        break;
                    case PlatFormEnum.LogService:
                        gethost = PlatFormApiHostOptions.LogService;
                        break;
                    default:
                        gethost = PlatFormApiHostOptions.BridgeService;
                        break;
                }
                return gethost;
            }
    
            /// <summary>
            ///  服务之间的网络请求,PostAsync异步处理
            /// </summary>
            /// <typeparam name="T">T 通常返回的实体数据</typeparam>
            /// <param name="_httpContext">请求上下文</param>
            /// <param name="_httpClientFactory">网络请求对象</param>
            /// <param name="hostEnum">服务枚举的一个域名,如:http://localhost:8081</param>
            /// <param name="requestApiUrlPath">服务的具体请求地址,开头为:/api/....如:/api/ReceAndSendMsgService/abc/testapi</param>
            /// <param name="dataDto">有数据的话约定为一个实体对象 如:var datatDto = new { Id = 1001, Name = "LMZ",Age=18 }</param>
            /// <param name="timeOut">默认连接超时时间为50秒</param>
            /// <paramref name="returnModel">默认true:返回实体数据;false:返回字符串</paramref>
            /// <returns></returns>
            public static async Task<T> PostAsync<T>(IHttpClientFactory _httpClientFactory, HttpContext _httpContext, string requestApiUrlPath, PlatFormEnum hostEnum = PlatFormEnum.BridgeService, object dataDto = null, int timeOut = 50)
            {
                if (string.IsNullOrEmpty(requestApiUrlPath))
                    throw new Exception("请求服务的具体接口地址不可以为空!");
                if (!requestApiUrlPath.Contains("/api"))
                    throw new Exception("接口地址错误,应该为如:/api/AbcService/****");
                string content = dataDto != null ? JsonConvert.SerializeObject(dataDto) : "0";
                var jsonDataStr = new StringContent(content, Encoding.UTF8, WebApiHeaderStrConst.Head_MediaType);
                var authVal = _httpContext.Request.Headers[WebApiHeaderStrConst.Head_Authorization].ToString().Replace(WebApiHeaderStrConst.Head_Authorization, "");
                using var client = _httpClientFactory.CreateClient();
                client.DefaultRequestHeaders.Add(WebApiHeaderStrConst.Head_Authorization, authVal);
                var connectTimeOut = timeOut <= 0 || timeOut > 180 ? 50 : timeOut;
                client.Timeout = TimeSpan.FromSeconds(connectTimeOut);
                var host = GetHostStrByConst(hostEnum);
                //string requesturl = $"{host}{requestApiUrlPath}";
                using (var httpResponseMsg = await client.PostAsync($"{host}{requestApiUrlPath}", jsonDataStr))
                {
                    if (httpResponseMsg.IsSuccessStatusCode)
                    {
                        var getstr = await httpResponseMsg.Content.ReadAsStringAsync();
                        Console.WriteLine("getStr=" + getstr);
                        return JsonConvert.DeserializeObject<T>(getstr);
                    }
                    else
                    {
                        throw new Exception("服务调用异常失败,请刷新再试!");
                    }
                };
            }
    
            /// <summary>
            /// 服务之间的网络请求,GetAsync异步处理
            /// </summary>
            /// <param name="_httpContext">请求上下文</param>
            /// <param name="_httpClientFactory">网络请求对象</param>
            /// <param name="hostEnum">服务枚举的一个域名,如:http://localhost:8081</param>
            /// <param name="RequestApiUrlPath">服务的具体请求地址,开头为:/api/.... 如:/api/ReceAndSendMsgService/abc/testapi</param>
            /// <param name="RequestDataDic">传输的数据字典 Dictionary<string, object> </param>
            /// <param name="timeOut">默认连接超时时间为50秒</param>
            /// <paramref name="returnModel">默认true:返回实体数据;false:返回字符串</paramref>
            /// <returns></returns>
            public static async Task<T> GetAsync<T>(IHttpClientFactory _httpClientFactory, HttpContext _httpContext, string RequestApiUrlPath, PlatFormEnum hostEnum = PlatFormEnum.BridgeService, Dictionary<string, object> RequestDataDic = null, int timeOut = 50, bool returnModel = true)
            {
                if (string.IsNullOrEmpty(RequestApiUrlPath))
                    throw new Exception("请求服务的具体接口地址不可以为空!");
                if (!RequestApiUrlPath.Contains("/api"))
                    throw new Exception("接口地址错误,应该为如:/api/AbcService/****");
                using var client = _httpClientFactory.CreateClient();
                var authVal = _httpContext.Request.Headers[WebApiHeaderStrConst.Head_Authorization].ToString().Replace(WebApiHeaderStrConst.Head_Authorization, "");
                client.DefaultRequestHeaders.Add(WebApiHeaderStrConst.Head_Authorization, authVal);
                var connectTimeOut = timeOut <= 0 || timeOut > 180 ? 50 : timeOut;
                client.Timeout = TimeSpan.FromSeconds(connectTimeOut);
                var sb = new StringBuilder();
                if (RequestDataDic != null)
                {
                    foreach (var dickey in RequestDataDic.Keys)
                        sb.Append($"&{dickey}={RequestDataDic[dickey]}");
                }
                var host = GetHostStrByConst(hostEnum);
                string requestData = $"{host}{RequestApiUrlPath}?lmz_temp=0{sb}";
                using (var httpResponseMsg = await client.GetAsync(requestData))
                {
                    if (httpResponseMsg.IsSuccessStatusCode)
                    {
                        var getstr = await httpResponseMsg.Content.ReadAsStringAsync();
                        Console.WriteLine("getStr=" + getstr + ", sbdata=" + sb);
                        return JsonConvert.DeserializeObject<T>(getstr);
                    }
                    else
                    {
                        throw new Exception("服务调用异常失败,请刷新再试!");
                    }
                };
            }
        }
    }
    如有疑问或者错误的地方,请跟帖,本人会第一时间答复以及相互学习,谢谢!个人会不断的上传自己的学习心得!

    好了今天就先到这里,下次有时间再更新,如果存在不合理的地方,欢迎大家多多指教留言!!!

    我的博客园地址:https://www.cnblogs.com/Fengge518

  • 相关阅读:
    蓝桥杯国赛--四阶幻方清晰易懂(dfs+剪枝,stl)
    蓝桥杯---九宫重排(典型bfs)
    快速排序算法细致总结!!!
    Topsis优劣解距离分析法
    golang变量的定义
    golang
    erlang的优缺点
    mongrel代码注解
    取石块 解题报告
    军队 解题报告
  • 原文地址:https://www.cnblogs.com/Fengge518/p/15216012.html
Copyright © 2011-2022 走看看