首页 > 其他分享 >YARP(Yet Another Reverse Proxy)Yarp是什么?

YARP(Yet Another Reverse Proxy)Yarp是什么?

时间:2024-01-13 22:01:23浏览次数:29  
标签:YARP Reverse Yarp new var using content

Azure应用服务用YARP取代了Nginx,获得了80%以上的吞吐量。他们每天处理160B多个请求(1.9 m RPS)。这是微软的一项了不起的技术创新。

首先我们来介绍一下什么是Yarp

Yarp是什么?

YARP(Yet Another Reverse Proxy)是一个开源的、高性能的反向代理库,由Microsoft开发,使用C#语言编写。它旨在作为.NET平台上构建反向代理服务器的基础。YARP主要针对.NET 5及以上版本,允许开发者在.NET应用程序中轻松地实现反向代理的功能。

YARP的主要特点和功能:

  1. 模块化和可扩展性: YARP设计成高度模块化的,这意味着可以根据需要替换或扩展内部组件,如HTTP请求路由、负载均衡、健康检查等。
  2. 性能: YARP针对高性能进行了优化,利用了.NET的异步编程模型和高效的IO操作,以处理大量并发连接。
  3. 配置驱动: YARP的行为可以通过配置来控制,支持从文件、数据库或其他来源动态加载配置。
  4. 路由: 可以基于各种参数(如路径、头部、查询参数)配置请求路由规则。
  5. 负载均衡: 内置多种负载均衡策略,如轮询、最少连接、随机选择等,并且可以自定义负载均衡策略。
  6. 健康检查: 支持后端服务的健康检查,以确保请求只会被转发到健康的后端服务实例。
  7. 转换器: 允许对请求和响应进行转换,如修改头部、路径或查询参数。
  8. 会话亲和性: 支持会话亲和性(Session Affinity),确保来自同一客户端的请求被发送到相同的后端服务实例。

使用YARP的一些场景:

  • 反向代理: 在客户端和后端服务之间提供一个中间层,用于请求转发和负载均衡。
  • API网关: 作为微服务架构中的API网关,提供路由、鉴权、监控等功能。
  • 边缘服务: 在应用程序和外部世界之间提供安全层,处理SSL终止、请求限制等任务。

Yarp简单的使用

创建一个WebApi的项目

安装Nuget

<ItemGroup>
	<PackageReference Include="Yarp.ReverseProxy" Version="2.0.0" />
</ItemGroup>

打开appsettings.json

{
 "Logging": {
   "LogLevel": {
     "Default": "Information",
     "Microsoft": "Warning",
     "Microsoft.Hosting.Lifetime": "Information"
   }
 },
 "AllowedHosts": "*",
 "ReverseProxy": {
   "Routes": {
     "route1" : {
       "ClusterId": "cluster1",
       "Match": {
         "Path": "{**catch-all}"
       }
     }
   },
   "Clusters": {
     "cluster1": {
       "Destinations": {
         "destination1": {
           "Address": "https://cn.bing.com/"
         }
       }
     }
   }
 }
}

打开Program.cs

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
app.MapReverseProxy();
app.Run();

然后启动项目,访问我们的api就会被代理转发到bing

Yarp工具代理使用

下面我们在提供一个在中间件使用yarp的方式

我们需要用到IHttpForwarder

先修改Program.cs 在这里我们注入了HttpForwarder,然后提供一个Run中间件,在中间件中手动指定了端点的地址https://cn.bing.com/ 然后我们启动一下项目。

using Yarp.ReverseProxy.Forwarder;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpForwarder(); // 注入IHttpForwarder 
var app = builder.Build();

var httpMessage = new HttpMessageInvoker(new HttpClientHandler());

app.Run((async context =>
{
    var httpForwarder = context.RequestServices.GetRequiredService<IHttpForwarder>();
    var destinationPrefix = "https://cn.bing.com/";

    await httpForwarder.SendAsync(context, destinationPrefix, httpMessage);
}));

app.Run();

也是一样会被代理过去,但是于简单使用不一样的是我们是在代码层面控制代理的。

使用yarp修改Bing的响应内容

我们继续基于上面的代理使用进行修改bing的相应内容!

打开Program.cs

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpForwarder(); // 注入IHttpForwarder 
var app = builder.Build();

var httpMessage = new HttpMessageInvoker(new HttpClientHandler()
{
    // 忽略https错误
    ServerCertificateCustomValidationCallback = (_, _, _, _) => true,
    AllowAutoRedirect = false,
    AutomaticDecompression = DecompressionMethods.GZip,
    UseCookies = false,
    UseProxy = false,
    UseDefaultCredentials = true,
});
var destinationPrefix = "https://cn.bing.com/";

var bingTransformer = new BingTransformer();

app.Run((async context =>
{
    var httpForwarder = context.RequestServices.GetRequiredService<IHttpForwarder>();
    await httpForwarder.SendAsync(context, destinationPrefix, httpMessage, new ForwarderRequestConfig(),
        bingTransformer);
}));

app.Run();

创建BingTransformer.cs

public class BingTransformer : HttpTransformer
{
    public override async ValueTask TransformRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest,
        string destinationPrefix,
        CancellationToken cancellationToken)
    {
        var uri = RequestUtilities.MakeDestinationAddress(destinationPrefix, httpContext.Request.Path,
            httpContext.Request.QueryString);
        proxyRequest.RequestUri = uri;
        proxyRequest.Headers.Host = uri.Host;
        await base.TransformRequestAsync(httpContext, proxyRequest, destinationPrefix, cancellationToken);
    }

    public override async ValueTask<bool> TransformResponseAsync(HttpContext httpContext,
        HttpResponseMessage? proxyResponse,
        CancellationToken cancellationToken)
    {
        await base.TransformResponseAsync(httpContext, proxyResponse, cancellationToken);

        if (httpContext.Request.Method == "GET" &&
            httpContext.Response.Headers["Content-Type"].Any(x => x.StartsWith("text/html")))
        {
            var encoding = proxyResponse.Content.Headers.FirstOrDefault(x => x.Key == "Content-Encoding").Value;
            if (encoding?.FirstOrDefault() == "gzip")
            {
                var content = proxyResponse?.Content.ReadAsByteArrayAsync(cancellationToken).Result;
                if (content != null)
                {
                    var result = Encoding.UTF8.GetString(GZipDecompressByte(content));
                    result = result.Replace("国内版", "Token Bing 搜索 - 国内版");
                    proxyResponse.Content = new StringContent(GZipDecompressString(result));
                }
            }
            else if (encoding.FirstOrDefault() == "br")
            {
                var content = proxyResponse?.Content.ReadAsByteArrayAsync(cancellationToken).Result;
                if (content != null)
                {
                    var result = Encoding.UTF8.GetString(BrDecompress(content));
                    result = result.Replace("国内版", "Token Bing 搜索 - 国内版");
                    proxyResponse.Content = new ByteArrayContent(BrCompress(result));
                }
            }
            else
            {
                var content = proxyResponse?.Content.ReadAsStringAsync(cancellationToken).Result;
                if (content != null)
                {
                    content = content.Replace("国内版", "Token Bing 搜索 - 国内版");
                    proxyResponse.Content = new StringContent(content);
                }
            }
        }

        return true;
    }

    /// <summary>
    /// 解压GZip
    /// </summary>
    /// <param name="bytes"></param>
    /// <returns></returns>
    public static byte[] GZipDecompressByte(byte[] bytes)
    {
        using var targetStream = new MemoryStream();
        using var compressStream = new MemoryStream(bytes);
        using var zipStream = new GZipStream(compressStream, CompressionMode.Decompress);
        using (var decompressionStream = new GZipStream(compressStream, CompressionMode.Decompress))
        {
            decompressionStream.CopyTo(targetStream);
        }

        return targetStream.ToArray();
    }

    /// <summary>
    /// 解压GZip
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static string GZipDecompressString(string str)
    {
        using var compressStream = new MemoryStream(Encoding.UTF8.GetBytes(str));
        using var zipStream = new GZipStream(compressStream, CompressionMode.Decompress);
        using var resultStream = new StreamReader(new MemoryStream(compressStream.ToArray()));
        return resultStream.ReadToEnd();
    }

    /// <summary>
    /// Br压缩
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public static byte[] BrCompress(string str)
    {
        using var outputStream = new MemoryStream();
        using (var compressionStream = new BrotliStream(outputStream, CompressionMode.Compress))
        {
            compressionStream.Write(Encoding.UTF8.GetBytes(str));
        }

        return outputStream.ToArray();
    }

    /// <summary>
    /// Br解压
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public static byte[] BrDecompress(byte[] input)
    {
        using (var inputStream = new MemoryStream(input))
        using (var outputStream = new MemoryStream())
        using (var decompressionStream = new BrotliStream(inputStream, CompressionMode.Decompress))
        {
            decompressionStream.CopyTo(outputStream);
            return outputStream.ToArray();
        }
    }
}

得到的效果我们将国内版修改成了Token Bing 搜索 - 国内版

Yarp AOT尝试

下面我们将Yarp进行AOT尝试,首先打开我们的项目,添加以下参数

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
    <PublishAot>true</PublishAot>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Yarp.ReverseProxy" Version="2.0.0" />
  </ItemGroup>
</Project>

AOT以后的大小15MB

测试转发并无问题

优化AOT大小,添加以下参数

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
    <PublishAot>true</PublishAot>

    <StackTraceSupport>false</StackTraceSupport>
    <OptimizationPreference>Size</OptimizationPreference>
    <PublishTrimmed>true</PublishTrimmed>
    <BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
    <EventSourceSupport>false</EventSourceSupport>
    <HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
    <EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
    <MetadataUpdaterSupport>false</MetadataUpdaterSupport>
    <UseNativeHttpHandler>true</UseNativeHttpHandler>
    <TrimMode>link</TrimMode>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Yarp.ReverseProxy" Version="2.0.0" />
  </ItemGroup>
</Project>

减少2MB左右,并且正常运行代理

Yarp相关资料

技术交流群:737776595

官方文档:https://microsoft.github.io/reverse-proxy/articles/getting-started.html

来着token的分享

标签:YARP,Reverse,Yarp,new,var,using,content
From: https://www.cnblogs.com/Leo_wl/p/17963049

相关文章

  • 波兰表达式(Polish Notation)和逆波兰表达式(Reverse Polish Notation)
    波兰表达式(Polishnotation)和逆波兰表达式(ReversePolishnotation)是两种表示数学表达式的方法,它们将运算符放在操作数之前或之后。1.波兰表达式(PolishNotation):-在波兰表达式中,运算符位于操作数之前。例如,常见的加法表达式"2+3"在波兰表达式中可以表示为"+23"。-波......
  • Java 实现List反转(reverse)的方法
    ​ List的反转是一种常见的操作,反转List会改变列表中元素的顺序,可以根据具体的需求在程序中实现不同的功能和行为。本文主要介绍Java中实现List反转(reverse)的方法,以及相关的示例代码。1、使用for循环实现使用for循环对List进行倒序遍历,添加到一个List中实现反转。代码示......
  • 记一道攻防世界上的Reverse-gametime
    一、题目描述把文件下载下来,运行后发现是一个简单的小游戏,属于那种玩通关了就给flag的,自己先玩了一下,玩了一下大概游戏规则就是看到s就按空格,遇到x就按x,遇到m就按m,但是玩到后面速度非常快,如果你足够厉害,玩到后面应该是可以玩出来的。这里我们就要IDA进行静态分析,又是小......
  • 『LeetCode』7. 整数反转 Reverse Integer
    题目描述给你一个32位的有符号整数x,返回将x中的数字部分反转后的结果。如果反转后整数超过32位的有符号整数的范围[−231,231−1],就返回0。假设环境不允许存储64位整数(有符号或无符号)。示例1:输入:x=123输出:321示例2:输入:x=-123输出:-321示例3:输入:x......
  • gdb Reverse Debugging
    参考:https://sourceware.org/gdb/current/onlinedocs/gdb.html/Reverse-Execution.html#Reverse-Executionhttps://www.cnblogs.com/liuhanxu/p/17011772.htmlhttps://blog.csdn.net/xungjhj/article/details/73727477?spm=1001.2101.3001.6650.1&utm_medium=distribute......
  • F. Shift and Reverse
    通过操作获得非递减数列,采用KMP算法求解。通过把一个数列打印两遍,遍历是否有长度为N的非递减数列或者非递增数列。通过计算求出最小操作数量。主要代码:#include<bits/stdc++.h>usingnamespacestd;constintN=200010;inta[N];intwork(intn){intindex=0,cnt=1,......
  • F. Shift and Reverse
    戳这里,看原题多重思想的巧妙结合不多说了,看代码就懂了#include<bits/stdc++.h>usingnamespacestd;intup[200006]={0},down[200006]={0};inta[200006]={0};intmain(){intt;cin>>t;while(t--){intn;cin>>n;for(inti......
  • 无涯教程-Erlang - reverse函数
    反转元素列表。reverse-语法reverse(lst)Lst  - 需要反转的元素列表。reverse-返回值返回元素的反向列表。-module(helloLearnfk).-import(lists,[reverse/1]).-export([start/0]).start()->Lst1=[1,2,3],io:fwrite("~p~n",[reverse(Lst1)]).......
  • Misc_XCTF_WriteUp | reverseMe
    题目分析把图片左右反转:提取文字,得到Flag。Flagflag{4f7548f93c7bef1dc6a0542cf04e796e}参考图片转文字在线-图片文字提取-网页OCR文字识别-白描网页版......
  • newstarctf2023 reverse 题解汇总
    newstarctf2023reverse题解汇总week1easy_REdie查无壳64直接IDA启动跟到main函数找到两部分flag拼起来就行了。flag{we1c0me_to_rev3rse!!}ELFdie查64ELFIDA启动稍微读一下写个py逆一下它的加密就行了flag{D0_4ou_7now_wha7_ELF_1s?}importbase64a="VlxRV......