日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

.NET Core 实例接口代理转发

發(fā)布時(shí)間:2024/9/3 asp.net 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET Core 实例接口代理转发 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  先講講本文的開發(fā)背景吧..

  在如今前后端分離的大背景下,咱的客戶又有要求啦~

  要前后端分離~ 然因?yàn)榉N種原因..沒辦法用用純前端的框架(其實(shí)是學(xué)習(xí)成本高,又沒錢請(qǐng)前端開發(fā)人員)...

  所以最終決定了一種方案..

  那就是采用MVC(只處理前端視圖層,單純是為了托管在.net core上)+Webapi的方式來實(shí)現(xiàn)前后端分離(講真,很奇葩)..

  那么問題就隨之而來了.

  現(xiàn)在主流的前端框架都是托管在nodejs上,是通過axios來訪問后端API,可以通過配置axios的代理配置(proxyTable)來實(shí)現(xiàn)跨域訪問.

  那么我們的JS運(yùn)行在MVC上,托管在.net core上..那咋辦呢?..沒有現(xiàn)成的轉(zhuǎn)發(fā)輪子..我們只有自己造了..

  所以這就是本篇的背景 - -.~

  正文

  幸運(yùn)的是ASP.NET Core 給我們提供了強(qiáng)大的中間件模式.

  我們完全可以通過定義一個(gè)轉(zhuǎn)發(fā)中間件的形式來實(shí)現(xiàn)代理接口轉(zhuǎn)發(fā),流程如圖:

  

  廢話不多說,我們來創(chuàng)建我們的中間件:

  一.創(chuàng)建檢測(cè)約定URL的接口與實(shí)現(xiàn)

  首先定義一個(gè)接口IUrlRewriter 用來檢測(cè)我們的URL是否有對(duì)應(yīng)前綴,如果有,則產(chǎn)生新的URL地址:

  這里我們定義接口是為了方便以后更好的更換注入類來實(shí)現(xiàn)快速更換檢測(cè)前綴的規(guī)則.

  public interface IUrlRewriter

  {

  Task?RewriteUri(HttpContext context);

  }

  實(shí)現(xiàn)這個(gè)接口,如下(解釋都在注釋里了):

  public class PrefixRewriter : IUrlRewriter

  {

  private readonly PathString _prefix; //前綴值

  private readonly string _newHost; //轉(zhuǎn)發(fā)的地址

  public PrefixRewriter(PathString prefix, string newHost)

  {

  _prefix=prefix;

  _newHost=newHost;

  }

  public Task?RewriteUri(HttpContext context)

  {

  if (context.Request.Path.StartsWithSegments(_prefix))//判斷訪問是否含有前綴

  {

  var newUri=context.Request.Path.Value.Remove(0, _prefix.Value.Length) + context.Request.QueryString;

  var targetUri=new Uri(_newHost + newUri);

  return Task.FromResult(targetUri);

  }

  return Task.FromResult((Uri)null);

  }

  }二.創(chuàng)建代理轉(zhuǎn)發(fā)需要的ProxyHttpClient

  創(chuàng)建獨(dú)立的ProxyHttpClient,主要是為了區(qū)分代理轉(zhuǎn)發(fā)的httpClient,方便后期添加日志或做別的處理.代碼如下:

  public class ProxyHttpClient

  {

  public HttpClient Client { get; private set; }

  public ProxyHttpClient(HttpClient httpClient)

  {

  Client=httpClient;

  }

  }三.創(chuàng)建代理轉(zhuǎn)發(fā)的中間件

  代碼如下,中間件嘛,主要就是Invoke方法了,說明可以看注釋.

  public class ProxyMiddleware

  {

  private ProxyHttpClient _proxyHttpClient;

  private const string CDN_HEADER_NAME="Cache-Control";

  private static readonly string[] NotForwardedHttpHeaders=new[] { "Connection", "Host" };

  private readonly RequestDelegate _next;

  private readonly ILogger?_logger;

  public ProxyMiddleware(

  RequestDelegate next,

  ILogger?logger,

  ProxyHttpClient proxyHttpClient

  )

  {

  _next=next;

  _logger=logger;

  _proxyHttpClient=proxyHttpClient;

  }

  ///

  /// 通過中間件,攔截訪問,檢測(cè)前綴,并轉(zhuǎn)發(fā)

  ///

  ///

  ///

  ///

  public async Task Invoke(HttpContext context, IUrlRewriter urlRewriter)

  {

  var targetUri=await urlRewriter.RewriteUri(context);

  if (targetUri !=null)

  {

  var requestMessage=GenerateProxifiedRequest(context, targetUri);

  await SendAsync(context, requestMessage);

  return;

  }

  await _next(context);

  }

  private async Task SendAsync(HttpContext context, HttpRequestMessage requestMessage)

  {

  using (var responseMessage=await _proxyHttpClient.Client.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))

  {

  context.Response.StatusCode=(int)responseMessage.StatusCode;

  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");

  if (!context.Response.Headers.ContainsKey(CDN_HEADER_NAME))

  {

  context.Response.Headers.Add(CDN_HEADER_NAME, "no-cache, no-store");

  }

  await responseMessage.Content.CopyToAsync(context.Response.Body);

  }

  }

  private static HttpRequestMessage GenerateProxifiedRequest(HttpContext context, Uri targetUri)

  {

  var requestMessage=new HttpRequestMessage();

  CopyRequestContentAndHeaders(context, requestMessage);

  requestMessage.RequestUri=targetUri;

  requestMessage.Headers=targetUri;

  requestMessage.Method=GetMethod(context.Request.Method);

  return requestMessage;

  }

  private static void CopyRequestContentAndHeaders(HttpContext context, HttpRequestMessage requestMessage)

  {

  var requestMethod=context.Request.Method;

  if (!HttpMethods.IsGet(requestMethod) &&

  !HttpMethods.IsHead(requestMethod) &&

  !HttpMethods.IsDelete(requestMethod) &&

  !HttpMethods.IsTrace(requestMethod))

  {

  var streamContent=new StreamContent(context.Request.Body);

  requestMessage.Content=streamContent;

  }

  foreach (var header in context.Request.Headers)

  {

  if (!NotForwardedHttpHeaders.Contains(header.Key))

  {

  if (header.Key !="User-Agent")

  {

  if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content !=null)

  {

  requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());

  }

  }

  else

  {

  string userAgent=header.Value.Count > 0 ? (header.Value[0] + " " + context.TraceIdentifier) : string.Empty;

  if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, userAgent) && requestMessage.Content !=null)

  {

  requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, userAgent);

  }

  }

  }

  }

  }

  private static HttpMethod GetMethod(string method)

  {

  if (HttpMethods.IsDelete(method)) return HttpMethod.Delete;

  if (HttpMethods.IsGet(method)) return HttpMethod.Get;

  if (HttpMethods.IsHead(method)) return HttpMethod.Head;

  if (HttpMethods.IsOptions(method)) return HttpMethod.Options;

  if (HttpMethods.IsPost(method)) return HttpMethod.Post;

  if (HttpMethods.IsPut(method)) return HttpMethod.Put;

  if (HttpMethods.IsTrace(method)) return HttpMethod.Trace;

  return new HttpMethod(method);

  }

  }四.注入和啟用我們的中間件和ProxyHttpClient

  我們?cè)赟tartup的ConfigureServices中添加如下代碼,注入我們的HttpClient與IUrlRewriter,如下:

  services.AddHttpClient()

  .ConfigurePrimaryHttpMessageHandler(x=> new HttpClientHandler()

  {

  AllowAutoRedirect=false,

  MaxConnectionsPerServer=int.MaxValue,

  UseCookies=false,

  }); //注入我們定義的HttpClient

  services.AddSingleton(new PrefixRewriter("/webapp", "localhost:63445"));//這里填寫前綴與需要轉(zhuǎn)發(fā)的地址

  然后在Startup的Configure中,啟動(dòng)我們的中間件,如下:

  app.UseMiddleware();

  五.測(cè)試中間件效果

  我們編寫前端代碼如下:

  created: function () {

  this.mockTableData1();

  axios.get("/webapp/api/values/get", "123").then(res=> { alert(res.data[0]) });

  axios.post("/webapp/api/values/post",{value: 'david'}).then(res=> { alert(res.data.message) });

  }

  在另外的WebApi項(xiàng)目,編寫接口如下:

  [HttpGet]

  public ActionResult> Get()

  {

  return new string[] { "value1", accstring.ToString() };

  }

  [HttpPost]

  public AjaxResult Post(dynamic value)

  {

  string aaa=JsonConvert.SerializeObject(value);

  return Success("OK");

  }

  效果如下,可以看到我們的視圖正確的獲取到了返回值:

  

  寫在最后

  這里我們通過中間件的形式實(shí)現(xiàn)了接口的代理轉(zhuǎn)發(fā),在具體的使用過程中肯定還會(huì)有一些小問題,而且這里我們只實(shí)現(xiàn)了Http的轉(zhuǎn)發(fā).ws的則沒有.

總結(jié)

以上是生活随笔為你收集整理的.NET Core 实例接口代理转发的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。