• Net Core中 使用Middleware 实现反向代理


    有这样的一个需求,我们要拦截某些特定的请求,并将它们重新定向到另一台服务器中,然而客户端并不知情。

    在NetCore中我们可以用中间件来实现,

    为什么要使用反向代理

      反向代理一般在下面的场景中进行使用:

    • 负载均衡:

      反向代理。它可以根据一些特定算法在一组相同的服务器之间分配请求负载,从而为系统的可伸缩性和可用性提供支持。

    • 网址重写:

      可以将无法更改的网络路径隐藏在反向代理后面。

    • 静态内容投放:

      反向代理服务器可以充当Web服务器。这使您可以将它们用于提供静态内容,例如HTML页面,JavaScript脚本,图像和其他文件,同时将对动态内容的请求转发到专用服务器。这是一种基于内容类型的负载平衡。

    • API网关:

      在具有微服务架构的系统中,您有多个服务器通过其API提供不同的服务。您可以使用反向代理来公开服务器API组合的单个入口点。

    • 多个网站合并:

      使多个网站使用共同的一个入口(网站),和微服务中的网关作用差不多。

    首先创建项目:

      我这里只有2.1 Version 的

      

    添加ProxyMiddleware

      

    ProxyMiddleware内容如下:

       代码不多有兴趣的朋友可以调试一下。这里还可以有很多的方向扩展。

     public class ProxyMiddleware
        {
            private static readonly HttpClient _httpClient = new HttpClient();
            private readonly RequestDelegate _nextRequestDelegate;
            private static readonly Uri _targetUri = new Uri("https://www.cnblogs.com/");
            public ProxyMiddleware(RequestDelegate nextMiddleware)
            {
                _nextRequestDelegate = nextMiddleware;
            }
            public async Task Invoke(HttpContext context)
            {
                bool validateUri = false; 
                if (context.Request.Path.StartsWithSegments("/api/values", out var Path))
                {
                    validateUri = true;
                }
                if (validateUri == true)
                {
                    var targetRequestMessage = CreateTargetMessage(context);
                    using (var responseMessage = await _httpClient.SendAsync(targetRequestMessage))
                    {
                        context.Response.StatusCode = (int)responseMessage.StatusCode;
                        CloneResponseHeadersIntoContext(context, responseMessage);
                        await responseMessage.Content.CopyToAsync(context.Response.Body);
                    }
                    return;
                }
                await _nextRequestDelegate(context);
            }
            private void CloneRequestContentAndHeaders(HttpContext context, HttpRequestMessage requestMessage)
            {
                foreach (var header in context.Request.Headers)
                {
                    requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                }
            }
            private HttpRequestMessage CreateTargetMessage(HttpContext context)
            {
                var requestMessage = new HttpRequestMessage();
                CloneRequestContentAndHeaders(context, requestMessage);
                requestMessage.RequestUri = _targetUri;
                requestMessage.Headers.Host = _targetUri.Host;
                requestMessage.Method = new HttpMethod(context.Request.Method);
                return requestMessage;
            }
            private void CloneResponseHeadersIntoContext(HttpContext context, HttpResponseMessage responseMessage)
            {
                foreach (var header in responseMessage.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }
                foreach (var header in responseMessage.Content.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }
                context.Response.Headers.Remove("Transfer-Encoding");
            }
        }

    添加管道

            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                app.UseMiddleware<ProxyMiddleware>();
                app.UseMvc();
            }

    运行结果:

      大家可以注意浏览器网址,以及显示的内容就可以了,(样式没了)

      

     代码解释:

      所有的描述在代码中,这里我只是标出这点代码的重点

            创建静态HttpClient连接,减少连接池数量
         private static readonly HttpClient _httpClient = new HttpClient();
          
    private readonly RequestDelegate _nextRequestDelegate;
         新的目标服务器
    private static readonly Uri _targetUri = new Uri("https://www.cnblogs.com/"); public ProxyMiddleware(RequestDelegate nextMiddleware) { _nextRequestDelegate = nextMiddleware; }
            
         所有的工作将由 Invoke执行
         public async Task Invoke(HttpContext context) { bool validateUri = false; if (context.Request.Path.StartsWithSegments("/api/values", out var Path)) { validateUri = true; } if (validateUri == true) { var targetRequestMessage = CreateTargetMessage(context); using (var responseMessage = await _httpClient.SendAsync(targetRequestMessage)) { context.Response.StatusCode = (int)responseMessage.StatusCode; CloneResponseHeadersIntoContext(context, responseMessage); await responseMessage.Content.CopyToAsync(context.Response.Body); } return; } await _nextRequestDelegate(context); }
            private void CloneResponseHeadersIntoContext(HttpContext context, HttpResponseMessage responseMessage)
            {
                foreach (var header in responseMessage.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }
                foreach (var header in responseMessage.Content.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }
           这里有一个坑大家注意了,有兴趣的同学可以调查研究一下,要是介绍的话可以单独开一篇了 context.Response.Headers.Remove(
    "Transfer-Encoding"); }

    有不足之处 希望大家指出相互学习。

            

  • 相关阅读:
    C#-获取页面源代码
    C#-获取页面源代码
    C#-窗体移动
    C#-窗体移动
    C#-窗体鼠标穿透
    C#-窗体鼠标穿透
    C#-string生成图片
    C#-string生成图片
    C#-Stmp发邮件
    POJ-1611 The Suspects
  • 原文地址:https://www.cnblogs.com/szlblog/p/11813770.html
Copyright © 2020-2023  润新知