Yarp 让系统内调度更灵活 http、https、websocket 反向代理
简介
Yarp 是微软团队开发的一个反向代理组件, 除了常规的 http 和 https 转换通讯,它最大的特点是可定制化,很容易根据特定场景开发出需要的定制代理通道。
详细介绍:https://devblogs.microsoft.com/dotnet/announcing-yarp-1-0-release
源码仓库:https://github.com/microsoft/reverse-proxy
文档地址 :https://microsoft.github.io/reverse-proxy/
基础使用
1、创建 ASP.NET Core 空项目
使用 Visual Studio :

dotnet new web -o MyProxy
2、 修改代码 Program.cs 文件
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
app.MapGet("/Ping", () => "Hello World!");
app.MapReverseProxy();
app.Run();
3、修改配置文件 appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ReverseProxy": {
"Routes": {
"routeAll": {
"ClusterId": "clusterBaidu",
"Match": {
"Path": "{**catch-all}"
}
}
},
"Clusters": {
"clusterBaidu": {
"Destinations": {
"baidu": {
"Address": "https://www.baidu.com/"
}
}
}
}
}
}
这里的配置是将所有的请求都转发到百度。
在 Program.cs 里,还注册了一个 Get 路由 Ping 。
4、启动项目

能够看到在浏览器访问程序监听的端口号后,显示的是百度的页面。打开 F12 ,看到请求头也是本地的,并不是百度的域名。
测试手动注册的路由 Ping :

能够显示正常。
5、问题整理
(1) Yarp 是不是只能做这种简单的转发?
不是,往下有配置文件说明。
(2) JSON 配置文件里有什么要注意的地方吗?
有。在这个演示的配置文件中 ReverseProxy:Clusters:cluster1:Destinations:destination1:Address 对应的值是:https://www.baidu.com/ ,如果去掉 www ,在项目启动后会跳转到百度首页,不是代理转发。去掉末尾的 / 符合没有任何影响。
(3) Yarp 会影响到程序中注册的路由吗?
不会影响到程序内部注册的路由。在 Program.cs 中无论 app.MapReverseProxy(); 在上还是在下,在访问 Ping 的时候,都是返回 Hello World!
var app = builder.Build();
app.MapReverseProxy();
app.MapGet("/Ping", () => "Hello World!");
app.Run();
进阶探索
1、多地址代理
修改配置文件 appsettings.json ,实现默认路由跳转百度,当访问 /movie 是访问 b站。
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ReverseProxy": {
"Routes": {
"routeBaidu": {
"ClusterId": "clusterBaidu",
"Match": {
"Path": "{**catch-all}"
}
},
"routeBiliBili": {
"ClusterId": "clusterBiliBili",
"Match": {
"Path": "/movie/{**catch-all}"
}
}
},
"Clusters": {
"clusterBaidu": {
"Destinations": {
"baidu": {
"Address": "https://www.baidu.com/"
}
}
},
"clusterBiliBili": {
"Destinations": {
"bilibili": {
"Address": "https://www.bilibili.com/"
}
}
}
}
}
}
测试结果:


在后面输入路由 /movie 后能够跳转到b站。但是b站网页没有完整显示,图片都没有,这是网站上的策略问题,对于数据接口没有这些问题。

详细的配置文件说明,可以查看 https://microsoft.github.io/reverse-proxy/articles/config-files.html
2、规则匹配
网页上太多资源,为了方便测试,启用两个 api 接口。地址分别是:http://localhost:5241/ 和 https://localhost:7184/
两个 api 接口中分别注册 /test 路由。
// http://localhost:5241/
app.MapGet("/test", () => "Welcome to Api111!");
// https://localhost:7184/
app.MapGet("/test", () => "Welcome to Api222!");
启动两个 api 程序。
C:\Users\Test>curl http://localhost:5241/test
Welcome to Api111!
C:\Users\Test>curl https://localhost:7184/test
Welcome to Api222!
修改 MyProxy 项目的配置文件 appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ReverseProxy": {
"Routes": {
"routeOne": {
"ClusterId": "clusterOne",
"Match": {
"Path": "/test/{**catch-all}",
"QueryParameters": [
{
"Name": "number",
"Values": [ "1" ]
}
]
}
},
"routeTwo": {
"ClusterId": "clusterTwo",
"Match": {
"Path": "/test/{**catch-all}",
"QueryParameters": [
{
"Name": "number",
"Values": [ "2" ]
}
]
}
},
"routeBaidu": {
"ClusterId": "clusterBaidu",
"Match": {
"Path": "{**catch-all}"
}
}
},
"Clusters": {
"clusterOne": {
"Destinations": {
"apiOne": {
"Address": "http://localhost:5241/"
}
}
},
"clusterTwo": {
"Destinations": {
"apiTwo": {
"Address": "https://localhost:7184/"
}
}
},
"clusterBaidu": {
"Destinations": {
"baidu": {
"Address": "https://www.baidu.com/"
}
}
}
}
}
}
Path :监听路由地址。
QueryParameters:匹配参数。
QueryParameters:Name:参数名。
QueryParameters:Values:参数值。
MyProxy 的监听端口是 http://localhost:5024/ 访问结果如下:
C:\Users\Test>curl http://localhost:5024/ping
Hello World!
C:\Users\Test>curl http://localhost:5024/test
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /test was not found on this server.</p>
</body></html>
C:\Users\Test>curl http://localhost:5024/test?number=1
Welcome to Api111!
C:\Users\Test>curl http://localhost:5024/test?number=2
Welcome to Api222!
能够根据参数以及参数值导向对应的地址。
3、问题整理
(1)为什么访问 /movie 不能正常显示网页。
因为 b站某些接口开启了防盗链,还有跨域检测。


(2)在根据参数匹配中,如果匹配的路由一样,监听的参数一样,参数值也一样会怎么样?
访问该路由地址会报错。
(3)路由匹配的优先级?
程序内注册的路由优先级最高,其次才是 Yarp 在配置文件里加载的。
小试牛刀
最近的工作是做企业内数据安全方面的。推动公司数据安全体系,通过技术手段提升公司信息安全。
有一个很老的OA系统,十几年了, .NET Framework 2.0 写的。漏洞一大堆,包括不限于xss、sql注入等,权限只到表单级别。浏览器上按下 F12 能查看到表单链接,直接复制出去,别人也能访问。
在这个系统上要做安全,我想的是在中间加代理,正好适合使用 Yarp 来完成,也方便写业务处理代码。嗯,很真实, .NET Core 写的,方便写业务代码。
用户登录成功后,会记录下用户的 Host 和 Cookie,每次访问的时候系统的时候,在 Yarp 这里都校验一下是否与用户登录时的匹配。
解决了两个问题:
1、从网络层捕获到所有的请求,方便后面做排查。参数、传值,出了事故可以找到责任人。
2、隔离真实的站点地址,杜绝弱安全等级网站暴露后被坏人攻击的风险。

踩坑集锦
1、non-ASCII
项目要代理某网页,在使用下载功能的时候,接口返回 502 。
info: Yarp.ReverseProxy.Forwarder.HttpForwarder[48]
ResponseHeaders: The destination returned a response that cannot be proxied back to the client.
System.InvalidOperationException: Invalid non-ASCII or control character in header: 0x00E4
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpHeaders.ThrowInvalidHeaderCharacter(Char ch)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpHeaders.ValidateHeaderValueCharacters(StringValues headerValues)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseHeaders.SetValueFast(String key, StringValues value)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpHeaders.Microsoft.AspNetCore.Http.IHeaderDictionary.set_Item(String key, StringValues value)
at Yarp.ReverseProxy.Forwarder.HttpTransformer.CopyResponseHeaders(HttpHeaders source, IHeaderDictionary destination)
at Yarp.ReverseProxy.Forwarder.HttpTransformer.TransformResponseAsync(HttpContext httpContext, HttpResponseMessage proxyResponse)
at Yarp.ReverseProxy.Transforms.Builder.StructuredTransformer.TransformResponseAsync(HttpContext httpContext, HttpResponseMessage proxyResponse)
at Yarp.ReverseProxy.Forwarder.HttpForwarder.SendAsync(HttpContext context, String destinationPrefix, HttpMessageInvoker httpClient, ForwarderRequestConfig requestConfig, HttpTransformer transformer)
去 GitHub 翻 Issues

下载接口能正常访问,文件流也能完整地拿到。重写了所有的响应头没有用。这种不开源的商业站点,也猜不到字符编码。
最后妥协了,用了一个 .NET 服务在服务器上下载后再转发。
代理非常规服务接口时,一定要多测试。
Yarp 让系统内调度更灵活 http、https、websocket 反向代理的更多相关文章
- Yarp 让系统内调度更灵活
简介 Yarp 是微软团队开发的一个反向代理组件, 除了常规的 http 和 https 转换通讯,它最大的特点是可定制化,很容易根据特定场景开发出需要的定制代理通道. 详细介绍:https://de ...
- nginx通过https方式反向代理多实例tomcat
案例说明:前面一层nginx+Keepalived部署的LB,后端两台web服务器部署了多实例的tomcat,通过https方式部署nginx反向代理tomcat请求.配置一如下: 1)LB层的ngi ...
- nginx证书制作以及配置https并设置访问http自动跳转https(反向代理转发jboss)
nginx证书制作以及配置https并设置访问http自动跳转https 默认情况下ssl模块并未被安装,如果要使用该模块则需要在编译时指定–with-http_ssl_module参数,安装模块依赖 ...
- NGINX之——配置HTTPS加密反向代理訪问–自签CA
转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46695495 出于公司内部訪问考虑,採用的CA是本机Openssl自签名生成的,因 ...
- NC 使用Nginx实现https的反向代理
summary: [通过Nginx实现NCC的https访问,并解决UClient应用的问题] 1 概述 通过Nginx 安装配置反向代理,实现NC.NCC的https访问. 本文以NCC2005为例 ...
- Nginx中配置http和https做反向代理
参考:http://www.zslin.com/web/article/detail/73 1.安装 sudo apt-get install nginx 2.配置: http_demo.conf # ...
- docker使用nginx实现ssl(https)反向代理其他容器应用
安装nginx容器 搜索nginx镜像 docker search nginx 拉取最新版nginx docker pull nginx:latest 运行容器 docker run --name=n ...
- Nginx设置Https反向代理,指向Docker Gitlab11.3.9 Https服务
目录 目录 1.GitLab11.3.9的安装 2.域名在阿里云托管,申请免费的1年证书 3.Gitlab 的 https 配置 4.Nginx 配置 https,反向代理指向 Gitlab 配置 目 ...
- Demo1_iOS9网络适配_改用更安全的HTTPS
iOS9把所有的http请求都改为https了:iOS9系统发送的网络请求将统一 使用TLS 1.2 SSL.采用TLS 1.2 协议,目的是 强制增强数据访问安全,而且 系统 Foundation ...
- graphicview和widgets没本质区别。它只是更轻量级,更灵活,性能更高的widgets
graphicview和widgets没本质区别.它只是更轻量级,更灵活,性能更高的widgets.核心就是把widgets变成了更轻量级的graphicitem,把QWidget的各种事件转换成了g ...
随机推荐
- 第十六篇:jQuery基础
一.jQuery和Dom的关系 http://jquery.cuishifeng.cn/ 模块,类库 DOM/BOM/JavaScript的类库: 二.jQuery选择器 1.查找元素 DOM: 10 ...
- centos6.5源码编译http2.4.9、虚拟主机、基于用户认证
centos6.5源码编译http2.4.9.虚拟主机.基于用户认证 2014-04-23 07:45 作者: 51linux 来源: 本站 浏览: 0 views 我要评论 字号: 大 中 ...
- 重新整理数据结构与算法(c#)—— 平衡二叉树[二十三]
前言 因为有些树是这样子的: 这样子的树有个坏处就是查询效率低,因为左边只有一层,而右边有3层,这就说明如果查找一个数字大于根元素的数字,那么查询判断就更多. 解决方法就是降低两边的层数差距: 变成这 ...
- 数据分布算法:hash+ 一致性 hash + redis cluster 的 hash slot
讲解分布式数据存储的核心算法,数据分布的算法 hash 算法 -> 一致性 hash 算法(memcached) -> redis cluster 的 hash slot 算法 用不同的算 ...
- 力扣626(MySQL)-换座位(中等)
题目: 表: Seat 编写SQL查询来交换每两个连续的学生的座位号.如果学生的数量是奇数,则最后一个学生的id不交换. 按 id 升序 返回结果表. 查询结果格式如下所示. 示例1: 解释: 请注意 ...
- 力扣71(java)-简化路径(中等)
题目: 给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 '/' 开头),请你将其转化为更加简洁的规范路径. 在 Unix 风格的文件系统中,一个点(.)表示当前目 ...
- MySQL统计信息不准导致的性能问题
简介: 统计信息不准导致错误的执行计划,引发性能问题 表的统计信息错误导致优化器选择错误的执行计划. 一个客户的性能优化案例: 没有修改数据库实例的任何配置参数以及业务代码没有变更的情况下,一条 sq ...
- Flink SQL 1.11 on Zeppelin 平台化实践
简介: 鉴于有很多企业都无法配备专门的团队来解决 Flink SQL 平台化的问题,那么到底有没有一个开源的.开箱即用的.功能相对完善的组件呢?答案就是本文的主角--Apache Zeppelin. ...
- RocketMQ 端云一体化设计与实践
简介:本文首先介绍了端云消息场景一体化的背景,然后重点分析了终端消息场景特点,以及终端消息场景支撑模型,最后对架构和存储内核进行了阐述.我们期望基于 RocketMQ 统一内核一体化支持终端和服务端不 ...
- C# - 能否让 SortedSet.RemoveWhere 内传入的委托异步执行
TL;DR; 若想充分利用 RemoveWhere 带来的性能优势,建议传入判断是否删除元素的委托内采取同步操作.若一定要在该委托内使用异步操作,可以采用本文中绕行的方法,但摈弃了 RemoveWhe ...