Yarp介绍

YARP是微软开源的用来代理服务器的反向代理组件,可实现的功能类似于nginx。

基于YARP,开发者可以非常快速的开发一个性能不错的小nginx,用于代理http(s)请求到上游的http(s)服务。

http穿透原理

同网现象

在http反向代理里,代理服务器总是上游服务的http客户端,为了网络性能,实际上上游服务总是和代理服务处在同一个局域网。试问一个问题:在公网的小nginx,如何把请求代理到局域网的http服务器?你会发现,小nginx做不到,因为小nginx所在公网服务器,无法直接与局域网的http服务器进行通信。

http穿透

在tcp里,进行连接时总是由客户端发起,但当连接之后客户端与服务端是平等的,他们之间可以双向收发数据。只要公网小nginx与局域网的http服务器存在tcp连接,我们可以使用这个连接做为httpClient的连接层,然后小nginx使用这个httpClient请求到局域网http服务器,而从达到http穿透效果。

完整流程

基于Yarp的http穿透

main连接

我们可以使用websocket协议,创建main连接,主要有以下好处:

  • 共享代理服务器监听的http(s)端口
  • 利用websocket的ping-pong实现连接检测
  • 利用websocket连接请求头进行身份认证

接收局域网创建的连接

我们可以为kestrel编写中间件,用获取获取局域网主动创建的tcp连接,这些连接与代理服务器与浏览器之间的连接共享同一个服务器端口,以下的listen.Use(transportService.OnConnectedAsync);是一个kestrel中间件。

public static IWebHostBuilder UseKestrelTransportChannel(this IWebHostBuilder hostBuilder)
{
return hostBuilder.UseKestrel(kestrel =>
{
var transportService = kestrel.ApplicationServices.GetRequiredService<TransportChannelService>();
var options = kestrel.ApplicationServices.GetRequiredService<IOptions<HttpMouseOptions>>().Value; var http = options.Listen.Http;
if (http != null)
{
kestrel.Listen(http.IPAddress, http.Port, listen =>
{
listen.Use(transportService.OnConnectedAsync);
});
} var https = options.Listen.Https;
if (https != null && File.Exists(https.Certificate.Path))
{
kestrel.Listen(https.IPAddress, https.Port, listen =>
{
listen.Protocols = HttpProtocols.Http1AndHttp2;
listen.UseHttps(https.Certificate.Path, https.Certificate.Password);
listen.Use(transportService.OnConnectedAsync);
});
}
});
}

绑定连接到HttpClient

Yarp进行代理时,需要指定HttpMessageInvoker,HttpMessageInvoker实际是SocketsHttpHandler的包装。而SocketsHttpHandler可以设置ConnectCallback属性,用于指定连接。

private static HttpMessageInvoker CreateHttpClient(TransportChannelService transportChannelService)
{
return new HttpMessageInvoker(new SocketsHttpHandler()
{
UseProxy = false,
UseCookies = false,
AllowAutoRedirect = false,
AutomaticDecompression = DecompressionMethods.None,
ConnectCallback = transportChannelService.CreateChannelAsync,
SslOptions = new SslClientAuthenticationOptions
{
RemoteCertificateValidationCallback = delegate { return true; }
}
});
}

Yarp直接转发

使用直接转发中间件

/// <summary>
/// 配置中间件
/// </summary>
/// <param name="app"></param>
/// <param name="connectionService"></param>
/// <param name="httpForwarderService"></param>
public void Configure(IApplicationBuilder app, IHostEnvironment hostEnvironment, ConnectionService connectionService, HttpForwarderService httpForwarderService)
{
app.UseWebSockets();
app.Use(connectionService.OnConnectedAsync);
app.Use(httpForwarderService.SendAsync);
}

通过请求的域名,找到局域网要转发的最终服务器地址,做为yarp的请求地址。

/// <summary>
/// 发送http数据
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
public async Task SendAsync(HttpContext httpContext, Func<Task> next)
{
var clientDomain = httpContext.Request.Host.Host;
if (this.connectionService.TryGetClientUpStream(clientDomain, out var clientUpstream))
{
var destPrefix = clientUpstream.ToString();
if (this.options.CurrentValue.HttpRequest.TryGetValue(clientDomain, out var requestConfig) == false)
{
requestConfig = this.defaultRequestConfig;
}
await this.httpForwarder.SendAsync(httpContext, destPrefix, httpClient, requestConfig, this.transformer);
}
}

总结

基于kestrel和SocketsHttpHandler高度可定制化的扩展能力,结合Yarp组件,我们可以很方便的开发一个支持内网http穿透的公网http反向代理服务器。如果把泛域名指向公网反向代理服务器,最终实现一个二级域名绑定流量到一个局域网http服务器的一对多功能。

最新文章

  1. XLT架构图(自己 画的)
  2. 【干货分享】JPager.Net MVC超好用轻量级分页控件
  3. 爬虫例子及知识点(scrapy知识点)
  4. C#分布式缓存二:Asp.Net中使用Couchbase
  5. 小心as&quot;陷阱&quot;(c#)
  6. 快速tab应用
  7. jquery冲突
  8. 3.4 C与汇编程序的相互调用
  9. git bash 出现vim的时候怎么退出
  10. ubuntu16.04下源码安装onos1.0.2
  11. PHP性能优化利器:生成器 yield理解
  12. 算法与数据结构(四) 图的物理存储结构与深搜、广搜(Swift版)
  13. pyhon 模块 IP/端口 扫描
  14. selenium 分布式 [WinError 10061] 由于目标计算机积极拒绝
  15. Python3 isinstance() 函数
  16. redis ERR This instance has cluster support disabled
  17. ubuntu 16.04 install wine
  18. struts2对拦截器使用带实例
  19. MongoDB学习之mongoose
  20. (原创)BZOJ 2038 小Z的袜子(hose) 莫队入门题+分块

热门文章

  1. vi /etc/sysconfig/network-scripts/ifcfg-enp0s3
  2. head tail diff -c fff hhh 前5行 后5行 区别 动态显示文本最新信息: $tail -f crawler.log
  3. Docker——Registry 通过Shell管理私有仓库镜像
  4. 027. Python面向对象的__init__方法
  5. kubectl cmd
  6. python字典转bytes类型字典
  7. GO语言复合类型01---指针
  8. ADAS感知算法观察
  9. 图像实例分割:CenterMask
  10. 智能驾驶L2发展策略