Net Core中 使用Middleware 實現反向代理

  • 2019 年 11 月 7 日
  • 筆記

有這樣的一個需求,我們要攔截某些特定的請求,並將它們重新定向到另一台服務器中,然而客戶端並不知情。

在NetCore中我們可以用中間件來實現,

首先創建項目:

  我這裡只有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"); }

 

有不足之處 希望大家指出相互學習。