翼度科技»论坛 编程开发 .net 查看内容

Welcome to YARP - 5.压缩、缓存

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
目录

Welcome to YARP - 1.认识YARP并搭建反向代理服务
Welcome to YARP - 2.配置功能
Welcome to YARP - 3.负载均衡
Welcome to YARP - 4.限流
Welcome to YARP - 5.身份验证和授权
Welcome to YARP - 6.压缩、缓存
Welcome to YARP - 7.健康检查
Welcome to YARP - 8.分布式跟踪
介绍

网关的 缓存压缩是常见的性能优化手段 ,用于提高系统的响应速度和降低网络传输的开销。
YARP 的 缓存压缩 其实也是 .NET 本身的功能。只需要配置 .NET 本身的缓存和压缩功能即可。
缓存

缓存的主要目的是优化性能、提高效率,减少对后端服务的负担。 我们可以对
频繁请求的静态数据或不经常更改的数据 进行 API 缓存,从而降低对后端服务的请求次数,提高响应速度,减轻后端服务的负载。
也可以对 静态资源 缓存 如:css、js、图像等,从而 加速页面加载速度,减轻服务器压力,提高用户体验。 等等。
基于 HTTP 的响应缓存

用于缓存的主 HTTP 标头是 Cache-Control,它用于指定缓存指令。 当请求从客户端到达服务器以及响应从服务器返回客户端时,这些指令控制缓存行为。 请求和响应在代理服务器之间移动,并且代理服务器还必须符合 HTTP 1.1 缓存规范。
Cache-Control  通用消息头字段,被用于在 http 请求和响应中,通过指定指令来实现缓存机制。缓存指令是单向的,这意味着在请求中设置的指令,不一定被包含在响应中。
要使用缓存,请求头中必须携带 Cache-Control 标头。同时响应头中也要做相应的设置。
下表中显示了常用 Cache-Control 指令
指令操作public缓存可以存储响应。private响应不得由共享缓存存储。 专用缓存可以存储和重用响应。max-age客户端不接受期限大于指定秒数的响应。 示例:max-age=60(60 秒),max-age=2592000(1 个月)no-cache请求时:缓存不能使用存储的响应来满足请求。 源服务器重新生成客户端的响应,中间件更新其缓存中存储的响应。  响应时:响应不得用于未经源服务器验证的后续请求。no-store请求时:缓存不得存储请求。  响应时:缓存不得存储任何部分的响应。相应的我们也要添加响应缓存中间件:
若要测试响应缓存,请使用 Fiddler、Postman 或其他可以显式设置请求标头的工具。显式设置上述的请求标头。
配置中间件

在 中 Program.cs ,将响应缓存中间件服务 AddResponseCaching 添加到服务集合中,并将应用配置为将中间件与 UseResponseCaching 扩展方法一起使用。 UseResponseCaching 将中间件添加到请求处理管道中:
  1. var builder = WebApplication.CreateBuilder(args);
  2. builder.Services.AddReverseProxy()//添加ReverseProxy相关服务到DI
  3.     .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));//从配置文件中加载ReverseProxy的设置
  4. builder.Services.AddResponseCaching(options =>
  5. {
  6.     options.UseCaseSensitivePaths = false; //确定是否将响应缓存在区分大小写的路径上。
  7.     options.SizeLimit = options.SizeLimit * 10; // 响应缓存中间件的大小限制(以字节为单位) 1G
  8. });
  9. var app = builder.Build();
  10. if (app.Environment.IsDevelopment())
  11. {
  12.     app.UseSwagger();
  13.     app.UseSwaggerUI();
  14. }
  15. // 使用 CORS 中间件时,必须在 UseResponseCaching 之前调用 UseCors。
  16. // app.UseCors();
  17. app.UseRouting();
  18. // 拦截请求并判断 请求头中是否包含 CacheControl 标头,如果没有则加上缓存标头
  19. app.Use(async (context, next) =>
  20. {
  21.     var header = context.Request.Headers;
  22.     var cacheControl = header.CacheControl;
  23.     if (!string.IsNullOrEmpty(header.CacheControl))
  24.     {
  25.         header.CacheControl = new Microsoft.Extensions.Primitives.StringValues("max-age");
  26.     }
  27.     await next(context);
  28. });
  29. app.UseResponseCaching();
  30. app.Use(async (context, next) =>
  31. {
  32.     context.Response.GetTypedHeaders().CacheControl =
  33.         new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
  34.         {
  35.             Public = true,
  36.             MaxAge = TimeSpan.FromSeconds(10)
  37.         };
  38.     context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] = new string[] { "Accept-Encoding" };
  39.     await next(context);
  40. });
  41. app.MapReverseProxy();
  42. app.MapGet("/", () => DateTime.Now.ToLongTimeString());
  43. app.Run();
复制代码
以上示例中:

  • Cache-Control:缓存可缓存响应长达10秒。
  • Vary:将中间件配置为仅当后续请求的 Accept-Encoding 标头与原始请求头匹配时才提供缓存的响应。
app.Use(async (context, next) =>
{
var header = context.Request.Headers;
var cacheControl = header.CacheControl;
if (!string.IsNullOrEmpty(header.CacheControl))
{
header.CacheControl = new Microsoft.Extensions.Primitives.StringValues("max-age");
}
  1. await next(context);
复制代码
});
可以看到我们先设置了 请求头的 缓存标头,如果 没有此 设置,几乎所有浏览器(标头值)都会发送 CacheControl:no-cache 或其他值,强制执行非缓存页面请求,这会导致 ResponseCachingMiddleware 实现忽略此请求(忽略缓存)并将其传递到服务器以检索数据。 如果你用 postman 或者 fiddle则可以主动这只CacheControl标头值为上述说的那几种。
上述示例中我们先 添加了 YARP 服务,然后添加了 AddResponseCaching 响应的缓存服务,然后拦截了请求并设置缓存标头,再开启了 UseResponseCaching() 响应缓存中间件。接下来设置了 [响应头的标头值]( ASP.NET Core 中的响应缓存中间件 | Microsoft Learn ),最后开启了 代理 中间件。源码已上传GitHub.
压缩

网络带宽是一种有限资源。 减小响应大小通常可显著提高应用的响应速度。 减小有效负载大小的一种方式是压缩应用的响应。 但是 YARP 默认是禁用解压缩的,因为它会增加 CPU 开销。
什么时候使用 响应压缩 中间件?
在 IIS、Apache 或 Nginx 中使用基于服务器的响应压缩技术。
而 HTTP.sys 服务器和 Kestrel 服务器当前不提供内置压缩支持,这时候就需要使用响应压缩中间件了。
我们使用 YARP 的直接转发来 演示一下 压缩功能,当然压缩是 .NET 本身自带的功能,你也可以通过添加压缩中间件来开启响应压缩。
代码示例:
  1. using System.Diagnostics;
  2. using System.Net;
  3. using Yarp.ReverseProxy.Forwarder;
  4. using Yarp.ReverseProxy.Transforms;
  5. var builder = WebApplication.CreateBuilder(args);
  6. builder.Services.AddHttpForwarder();
  7. // Add services to the container.
  8. var app = builder.Build();
  9. // Configure our own HttpMessageInvoker for outbound calls for proxy operations
  10. var httpClient = new HttpMessageInvoker(new SocketsHttpHandler()
  11. {
  12.     UseProxy = false,
  13.     AllowAutoRedirect = false,
  14.     AutomaticDecompression = DecompressionMethods.GZip, // 设置响应压缩方式
  15.     UseCookies = false,
  16.     ActivityHeadersPropagator = new ReverseProxyPropagator(DistributedContextPropagator.Current),
  17.     ConnectTimeout = TimeSpan.FromSeconds(15),
  18. });
  19. // Setup our own request transform class
  20. var transformer = new CustomTransformer(); // or HttpTransformer.Default;
  21. var requestConfig = new ForwarderRequestConfig { ActivityTimeout = TimeSpan.FromSeconds(100) };
  22. app.UseRouting();
  23. // Configure the HTTP request pipeline.
  24. app.MapForwarder("/{**catch-all}", "http://localhost:5047", requestConfig, transformer, httpClient);
  25. app.Run();
  26. /// <summary>
  27. /// 自定义请求转换
  28. /// </summary>
  29. class CustomTransformer : HttpTransformer
  30. {
  31.     ///<summary>
  32.     /// A callback that is invoked prior to sending the proxied request. All HttpRequestMessage
  33.     /// fields are initialized except RequestUri, which will be initialized after the
  34.     /// callback if no value is provided. The string parameter represents the destination
  35.     /// URI prefix that should be used when constructing the RequestUri. The headers
  36.     /// are copied by the base implementation, excluding some protocol headers like HTTP/2
  37.     /// pseudo headers (":authority").
  38.     ///</summary>
  39.     ///<param name="httpContext">传入请求</param>
  40.     ///<param name="proxyRequest">传出的代理请求</param>
  41.     ///<param name="destinationPrefix">所选目标服务器的uri前缀,可用于创建RequestUri</param>
  42.     public override async ValueTask TransformRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest, string destinationPrefix, CancellationToken cancellationToken)
  43.     {
  44.         // 转发所有头部信息
  45.         await base.TransformRequestAsync(httpContext, proxyRequest, destinationPrefix, cancellationToken);
  46.         // 自定义查询query 值
  47.         var queryContext = new QueryTransformContext(httpContext.Request);
  48.         queryContext.Collection.Remove("param1");
  49.         queryContext.Collection["s"] = "xx2";
  50.         // 分配自定义 URI。在此处连接时请注意额外的斜杠。RequestUtilities.MakeDestinationAddress 是一个安全的默认值。
  51.         proxyRequest.RequestUri = RequestUtilities.MakeDestinationAddress("http://localhost:5047", httpContext.Request.Path, queryContext.QueryString);
  52.         // 禁止原始请求标头,使用目标 Uri 中的标头
  53.         proxyRequest.Headers.Host = null;
  54.     }
  55. }
复制代码
上述示例中,我们使用了 YARP 的直接转发模式,不需要添加 YARP 服务和中间件,但是要添加 这个东西 AddHttpForwarder,然后配置 自定义请求转换 类。并开启 压缩模式为 GZip。
如果想看效果记得使用fiddle 抓取请求的返回值查看原始请求,因为postman和浏览器客户端 都会默认对常用的压缩格式的数据进行解压缩。
如果服务器本身支持压缩,请使用 基于服务器的压缩技术。而 HTTP.sys 服务器和 Kestrel 服务器 是不支持压缩技术的,所以这时候才考虑使用 压缩中间件。
总结

本章我们介绍了 YARP 的缓存和压缩功能,其实也都是 .NET 自身的功能,如果了解使用过 .NET的 缓存 和 压缩 中间件很容易就能理解。本章示例代码已上传GitHub,建议把代码down下来自己实验一下,再去配合理解。
有什么问题欢迎留言交流。
下篇文章我们继续介绍 YARP 的健康检查功能。

来源:https://www.cnblogs.com/condding-y/archive/2023/11/13/17828298.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具