NET Core微服务之路:基于Ocelot的API网关Relay实现--RPC篇
前言

. Accept:*/*
2. Accept-Encoding:gzip, deflate
3. Accept-Language:zh-CN,zh;q=0.9,en;q=0.8
4. Cache-Control:no-cache
5. Connection:keep-alive
6. Cookie:.AUTH=A24BADC9D552CF1157B7842F2A6C159A681CA330DBB449568896FAC839CFEE51F42973C9A5B9F632418FB82C128A8BF612D27C2EE7DABDE985E9A79DF19A955FFED9E8219853FB90574B0990DD29B2B7ED23A7C26B8AD1934870B8C0FCB4F577636E267003E6D214D9B319A4739D3716E2A8299C35E228F96EC12A29CCDE83A7D2D3B24EE6A84CF2D69D81A44E0F46EC9B112BDAA9FC0E0943DB36C1449FD79E6D5A123E5D182D2C3A03D4049CBD76947D33EB5DCCE82CB1C91ACACD83B6D07F19A6629732FA16D08443450DC2937C7CEF6A2FAE941760C79064C7A5A67E844ABDA2DE89E5B10F3B30B8A89CEDE9C00A3C79711D
7. Host:erp-dev.holderzone.cn:90
8. Pragma:no-cache
9. Referer:http://erp-dev.holderzone.cn:90/
10. User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36

Ocelot下游中间件扩展
.png)
.png)
namespace DotEasy.Rpc.ApiGateway
{
public static class OcelotPipelineConfigurationExtensions
{
public static void AddRpcMiddleware(this OcelotPipelineConfiguration config)
{
config.MapWhenOcelotPipeline.Add(builder => builder.AddRpcMiddleware());
} private static Func<DownstreamContext, bool> AddRpcMiddleware(this IOcelotPipelineBuilder builder)
{
builder.UseHttpHeadersTransformationMiddleware();
builder.UseDownstreamRequestInitialiser();
builder.UseRateLimiting();
builder.UseRequestIdMiddleware();
builder.UseDownstreamUrlCreatorMiddleware();
builder.UseRpcRequesterMiddleware();
return context => context.DownstreamReRoute.DownstreamScheme.Equals("tcp", StringComparison.OrdinalIgnoreCase);
}
}
}
using Ocelot.Middleware.Pipeline; namespace DotEasy.Rpc.ApiGateway
{
public static class RpcRequesterMiddlewareExtensions
{
public static void UseRpcRequesterMiddleware(this IOcelotPipelineBuilder builder)
{
builder.UseMiddleware<RelayRequesterMiddleware>();
}
}
}
using System;
using System.Net;
using System.Threading.Tasks;
using Ocelot.Logging;
using Ocelot.Middleware; namespace DotEasy.Rpc.ApiGateway
{
public class RelayRequesterMiddleware : OcelotMiddleware
{
private readonly OcelotRequestDelegate _next;
private readonly IOcelotLogger _logger; public RelayRequesterMiddleware(OcelotRequestDelegate next, IOcelotLoggerFactory loggerFactory) : base(loggerFactory .CreateLogger<RelayRequesterMiddleware>())
{
_next = next;
_logger = loggerFactory.CreateLogger<RelayRequesterMiddleware>();
} public async Task Invoke(DownstreamContext context)
{
var httpContent = ... // TODO:协议转换处理等操作
context.DownstreamResponse = new DownstreamResponse(httpContent, HttpStatusCode.OK, context.DownstreamRequest.Headers);
await _next.Invoke(context);
}
}
}
app.UseOcelot(pipelineConfiguration => pipelineConfiguration.AddRpcMiddleware()).Wait();
以上便完成了对Ocelot中DownstreamContext的扩展,
总结下来,当我们需要扩展下游协议时,我们需要手动配置OcelotPipelineConfiguration并添加到IOcelotPipelineBuilder中,然后通过扩展IOcelotPipelineBuilder实现下游中间件的自定义处理。
手动协议转换
var httpContent = relayHttpRouteRpc.HttpRouteRpc(ClientProxy.GenerateAll(new Uri("http://127.0.0.1:8500")),
new Uri(context.DownstreamRequest.ToUri()),
context.DownstreamRequest.Headers); // 目前尚未处理Headers消息头
- 在Doteasy.RPC单次调用中,为了减少众多接口生成代理所带来的耗时,每次调用前都会检查相关接口的动态代理是否已经生成,确保每次只生成一个片段的代理。然而,作为一个网关中的中继器,这样一次生成一个代码片段显得非常无力,需要将所有的接口全部生成代理,以方便在Relay中查找和调用。
- 再看一个RESTful风格中的URL:http://127.0.0.1:8080/api/1/Sync,一般我们将谓词放置最后,而参数一般放置在谓词的前面,在手动转换RPC的过程中,就可以利用谓词来假设我们需要调用的RPC服务名称(但实际不一定就是Sync)。
- 基于Doteasy.RPC中的服务容器,可以很方便的实现参数类型转换以及后期的Headers处理。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using DotEasy.Rpc.Core.Runtime.Client;
using DotEasy.Rpc.Core.Runtime.Communally.Convertibles;
using Newtonsoft.Json; namespace DotEasy.Rpc.Core.ApiGateway.Impl
{
public class DefaultRelayHttpRouteRpc : IRelayHttpRouteRpc
{
private IRemoteInvokeService _remoteInvokeService;
private ITypeConvertibleService _typeConvertibleService; public DefaultRelayHttpRouteRpc(IRemoteInvokeService remoteInvokeService, ITypeConvertibleService typeConvertibleService)
{
_remoteInvokeService = remoteInvokeService;
_typeConvertibleService = typeConvertibleService;
} public StringContent HttpRouteRpc(List<dynamic> proxys, Uri urlPath, HttpRequestHeaders headers)
{
foreach (var proxy in proxys)
{
Type type = proxy.GetType();
if (!urlPath.Query.Contains("scheme=rpc")) continue; var predicate = urlPath.AbsolutePath.Split('/');
var absName = predicate[predicate.Length - ];
var absPars = predicate[predicate.Length - ]; if (!type.GetMethods().Any(methodInfo => methodInfo.Name.Contains(absName))) continue; var method = type.GetMethod(absName);
if (method != null)
{
var parameters = method.GetParameters();
var parType = parameters[].ParameterType; // only one parameter
var par = _typeConvertibleService.Convert(absPars, parType); var relayScriptor = new RelayScriptor {InvokeType = type, InvokeParameter = new dynamic[] {par}}; var result = method.Invoke(
Activator.CreateInstance(relayScriptor.InvokeType, _remoteInvokeService, _typeConvertibleService),
relayScriptor.InvokeParameter); var strResult = JsonConvert.SerializeObject(result);
return new StringContent(strResult);
}
} return null;
}
}
}
- 当http中多个参数时,无法进行协议转换,因为不知道代理目标方法的参数集合是多少,只有全局假设一对一的参数目标。
- RPC客户端在网关中集成了大量的代理生成,无法实现动态更新,例如原来手动替换DLL,接口自动更新动态代理。
- 每一次调用都需要从大量的代理中查找指定(或模糊匹配)的方法名称,如果存在1KW+的接口名称,这个查找将是一个非常严重的瓶颈。
总结
NET Core微服务之路:基于Ocelot的API网关Relay实现--RPC篇的更多相关文章
- .NET Core微服务之路:文章系列和内容索引汇总 (v0.52)
微服务架构,对于从事JAVA架构的童鞋来说,早已不是什么新鲜的事儿,他们有鼎鼎大名的Spring Cloud这样的全家桶框架支撑,包含微服务核心组件如 1. Eureka:实现服务注册与发现. 2. ...
- .NET Core微服务之路:不断更新中的目录 (v0.43)
原文:.NET Core微服务之路:不断更新中的目录 (v0.43) 微服务架构,对于从事JAVA架构的童鞋来说,早已不是什么新鲜的事儿,他们有鼎鼎大名的Spring Cloud这样的全家桶框架支撑, ...
- NET Core微服务之路:实战SkyWalking+Exceptionless体验生产环境下的追踪系统
前言 当一个APM或一个日志中心实际部署在生产环境中时,是有点力不从心的. 比如如下场景分析的问题: 从APM上说,知道某个节点出现异常,或延迟过过高,却不能及时知道日志反馈情况,总不可能去相应的节点 ...
- NET Core微服务之路:实战SkyWalking+Exceptionless体验生产下追踪系统
原文:NET Core微服务之路:实战SkyWalking+Exceptionless体验生产下追踪系统 前言 当一个APM或一个日志中心实际部署在生产环境中时,是有点力不从心的. 比如如下场景分析的 ...
- .NET Core微服务之基于Ocelot实现API网关服务
Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.啥是API网关? API 网关一般放到微服务的最前端,并且要让API 网关变成由应用所发起的每个请求的入口.这样就可以明显的简化客户端 ...
- .NET Core微服务之基于Ocelot实现API网关服务(续)
Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.负载均衡与请求缓存 1.1 负载均衡 为了验证负载均衡,这里我们配置了两个Consul Client节点,其中ClientServic ...
- 基于.net core微服务(Consul、Ocelot、Docker、App.Metrics+InfluxDB+Grafana、Exceptionless、数据一致性、Jenkins)
1.微服务简介 一种架构模式,提倡将单一应用程序划分成一组小的服务,服务之间互相协调.互相配合,为用户提供最终价值.每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(RESTfu ...
- NET Core微服务之路:自己动手实现Rpc服务框架,基于DotEasy.Rpc服务框架的介绍和集成
本篇内容属于非实用性(拿来即用)介绍,如对框架设计没兴趣的朋友,请略过. 快一个月没有写博文了,最近忙着两件事; 一:阅读刘墉先生的<说话的魅力>,以一种微妙的,你我大家都会经常遇见 ...
- .NET Core微服务之路:基于gRPC服务发现与服务治理的方案
重温最少化集群搭建,我相信很多朋友都已经搭建出来,基于Watch机制也实现了出来,相信也有很多朋友有了自己的实现思路,但是,很多朋友有个疑问,我API和服务分离好了,怎么通过服务中心进行发现呢,这个过 ...
随机推荐
- 关于Java中static关键字的用法以及从内存角度解析
在Java中,static可以用来修饰成员变量和成员方法. 修饰成员变量,称为静态成员方法 修饰静态方法,称为静态成员方法 搞清楚用法和区别之前,先搞清static声明的变量和普通非静态变量在内存的分 ...
- oracle查询某张表的外键,并用 truncate 命令有外键的表中的数据
注:本文来源于<oracle查询某张表的外键(最终解决办法)> 一:几个查询表外键的脚本 select b.table_name, b.column_name from user_cons ...
- shell 运算符章节笔记
// 运算符 算数运算符 关系运算符 布尔运算符 字符串运算符 文件运算符 1.算数运算符 + - * / % = == != echo `expr 1 + 1`; echo `expr 1 - 2` ...
- iOS UIView Class Translation
类 UIView 一个管理屏幕上矩形区域内容的对象. 概述 Views 是你应用的用户界面最基础的组成部分.UIView类定义了对于所有 views 的共有的行为.一个 view 对象在它的边界矩 ...
- centos6.9 改系统语言成中文简体
1.在root权限下 切换到root下:su root 查看当前语言环境:locale -a (注意中间有空格) 如果看到 zh_CN.UTF-8(这个是中文简体)说明你的系统支持中文语言 2.编辑 ...
- Docker 踩坑记(failed to build: Get https://registry-1.docker.io/v2/microsoft/dotnet/manifests/2.1-sdk: unauthorized: incorrect username or password)
今天看了下.net core 示例项目eShopWebOnline. 无奈在使用docker的时候总是提示一下错误信息,大致信息是用户名密码错误.但是,明明桌面右下角Docker帐号处于登录状态. E ...
- PHP金钱数字转金钱大写
/* * 数字金额转换成中文大写金额的函数 * String Int $num 要转换的小写数字或小写字符串 * return 大写数字 */ function num_to_rmb($num){ $ ...
- C++多态及其实现原理
1. 多态的定义:多态含义为一个事物有多种形态.在C ++程序设计中,多态性是指具有不同功能的函数可以用同一个函数名,这样就可以用一个函数名调用不同内容的函数,主要分为静态多态和动态多态: 静态 ...
- 理解go的闭包
package main import ( "fmt" ) func test(a int) { a++ fmt.Println(a) } func test2() func() ...
- 用Python建立连接直接读取与更改Rockwell Control Logix Controller的tag值
请参考如下连接的开源项目 源代码在本地测试好用. 注: 这里所用的Python 版本是 2.7.11 https://github.com/dmroeder/pylogix