将 POST 请求从 asp.net 核心控制器转发到不同的 URL

Posted

技术标签:

【中文标题】将 POST 请求从 asp.net 核心控制器转发到不同的 URL【英文标题】:Forward POST request from asp.net core controller to different URL 【发布时间】:2019-12-04 11:55:56 【问题描述】:

我想在不使用中间件的情况下将传入的 POST 请求“按原样”(包括标头、正文、源数据)转发到我的 asp.net 核心控制器到不同的 URL。

我为 asp.net 找到了一个示例:https://philsversion.com/2012/09/06/creating-a-proxy-with-apicontroller/

但这不适用于 asp.net 核心,因为调用 返回等待 http.SendAsync(this.Request); 在 asp.net core 中接受一个 HttpRequestMessage 并且 Request 对象的类型是 HttpRequest。

我还发现了一些代码,它从 HttpRequest 创建了一个 HttpRequestMessage,请参阅:Convert Microsoft.AspNetCore.Http.HttpRequest to HttpRequestMessage

使用此代码,接收端点(我转发到的)获取正文,但没有获取表单字段。

检查类 HttpRequestMessage 我发现它不包含 FormFields 的属性。

[Microsoft.AspNetCore.Mvc.HttpPost]
[NrgsRoute("api/redirect-v1/key")]
public async Task<HttpResponseMessage> Forward(
   [FromUri] string key,
   CancellationToken cancellationToken)

   // the URL was shortened, we need to get the original URL to which we want to forward the POST request
   var url = await _shortenUrlService.GetUrlFromToken(key, cancellationToken).ConfigureAwait(false);

     using (var httpClient = new HttpClient())
     
         var forwardUrl = new Uri(url);
         Request.Path = new PathString(forwardUrl.PathAndQuery);

         // see: https://***.com/questions/45759417/convert-microsoft-aspnetcore-http-httprequest-to-httprequestmessage
         var requestMessage = Request.ToHttpRequestMessage();
         return await httpClient.SendAsync(requestMessage, cancellationToken);

         // Problem: Forwards header and body but NOT form fields
     
 

预期的结果是在我的接收端点我有相同的 - 标题 - 身体 - 表单域 与原始 POST 请求一样。

【问题讨论】:

感谢您的问答!你拯救了我的一天! 【参考方案1】:

我最终做了以下事情:

[HttpPost]
[NrgsRoute("api/redirect-v1/key")]
public async Task<RedirectResult> Forward(string key, CancellationToken cancellationToken)

    var url = await _shortenUrlService.GetUrlFromToken(key, cancellationToken).ConfigureAwait(false);
    if (string.IsNullOrEmpty(url))
        throw new BadRequestException($"Could not create forward URL from parameter key", "redirect-error");

    using (var httpClient = new HttpClient())
    
        var forwardUrl = new Uri(url);
        Request.Path = new PathString(forwardUrl.PathAndQuery);

        HttpResponseMessage responseMessage;
        if (Request.HasFormContentType)
            responseMessage = await ForwardFormData(key, httpClient, forwardUrl, cancellationToken);
        else
            responseMessage = await ForwardBody(key, httpClient, cancellationToken);

        var queryParams = forwardUrl.GetQueryStringParams();
        var lUlr = queryParams["lurl"];
        return new RedirectResult(lUlr);
    


private async Task<HttpResponseMessage> ForwardFormData(string key, HttpClient httpClient, Uri forwardUrl, CancellationToken cancellationToken)

    var formContent = new List<KeyValuePair<string, string>>();
    HttpResponseMessage result;

    if (Request.ContentType == "application/x-www-form-urlencoded")
    
        foreach (var formKey in Request.Form.Keys)
        
            var content = Request.Form[formKey].FirstOrDefault();
            if (content != null)
                formContent.Add(new KeyValuePair<string, string>(formKey, content));
        
        var formUrlEncodedContent = new FormUrlEncodedContent(formContent);
        result = await httpClient.PostAsync(forwardUrl, formUrlEncodedContent, cancellationToken);
    
    else
    
        var multipartFormDataContent = new MultipartFormDataContent();
        foreach (var formKey in Request.Form.Keys)
        
            var content = Request.Form[formKey].FirstOrDefault();
            if (content != null)
                multipartFormDataContent.Add(new StringContent(content), formKey);
        

        result = await httpClient.PostAsync(forwardUrl, multipartFormDataContent, cancellationToken);
    

    return result;


private async Task<HttpResponseMessage> ForwardBody(string key, HttpClient httpClient, CancellationToken cancellationToken)

    // we do not have direct access to Content, see: https://***.com/questions/41508664/net-core-forward-a-local-api-form-data-post-request-to-remote-api

    var requestMessage = Request.ToHttpRequestMessage();
    return await httpClient.SendAsync(requestMessage, cancellationToken);

【讨论】:

以上是关于将 POST 请求从 asp.net 核心控制器转发到不同的 URL的主要内容,如果未能解决你的问题,请参考以下文章