.NET Core将本地API表单数据发布请求转发到远程API

时间:2017-01-06 15:18:10

标签: c# asp.net-core asp.net-core-mvc .net-core

我有一个AJAX表单,它将表单数据发布到本地API网址:/api/document。它包含一个文件和一个自定义ID。我们只想获取确切收到的请求,并将其转发到example.com:8000/document/upload的远程API。

是否有一种简单的方法可以使用Asp.NET Core实现对远程API的请求“转发”(或代理?)?

下面我们想到简单地使用Web API Http客户端来获取请求然后重新发送它(通过这样做我们希望能够例如从后端附加私有api密钥 ),但似乎无法正常工作,PostAsync不接受Request

Ajax发送的原始请求

POST http://localhost:62640/api/document HTTP/1.1
Host: localhost:62640
Connection: keep-alive
Content-Length: 77424
Accept: application/json
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryn1BS5IFplQcUklyt
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8,fr;q=0.6

------WebKitFormBoundaryn1BS5IFplQcUklyt
Content-Disposition: form-data; name="fileToUpload"; filename="test-document.pdf"
Content-Type: application/pdf
...
------WebKitFormBoundaryn1BS5IFplQcUklyt
Content-Disposition: form-data; name="id"

someid
------WebKitFormBoundaryn1BS5IFplQcUklyt--

后端代码

我们的.NET Core后端有一个简单的“转发到另一个API”的目的。

public class DocumentUploadResult
{
     public int errorCode;
     public string docId;
}

[Route("api/[controller]")]
public class DocumentController : Controller
{
    // POST api/document
    [HttpPost]
    public async Task<DocumentUploadResult> Post()
    {
        client.BaseAddress = new Uri("http://example.com:8000");

        client.DefaultRequestHeaders.Accept.Clear();
        HttpResponseMessage response = await client.PostAsync("/document/upload", Request.Form);
        if (response.IsSuccessStatusCode)
        {
            retValue = await response.Content.ReadAsAsync<DocumentUploadResult>();
        }
        return retValue;
    }
}

我们有一个GET请求(此处未转载)可以正常使用。因为它不必从本地POST数据中获取数据。

我的问题

如何简单地传递传入的本地HttpPost请求并将其转发到远程API?

我在stackoverflow或网络上搜索了很多,但所有这些资源都是关于将Request.Content转发到遥控器的旧资源。

但是在Asp.NET Core 1.0上,我们无法访问Content。我们只能检索Request.Form(也不是Request.Body),然后将其作为PostAsync方法的参数接受:

  

无法从Microsoft.AspNetCore.Http.IformCollection转换为   System.Net.Http.HttpContent

我有想法直接将请求传递给postAsync:

  

无法从Microsoft.AspNetCore.Http.HttpRequest转换为   System.Net.Http.HttpContent

我不知道如何根据我收到的本地请求重建预期的HttpContent

预期回复

有关信息,当我们使用自定义Id和上传的文件发布有效的表单数据时,远程(example.com)API响应为:

{
  "errorCode": 0
  "docId": "585846a1afe8ad12e46a4e60"
}

1 个答案:

答案 0 :(得分:6)

好的,首先创建一个视图模型来保存表单信息。由于涉及文件上传,请在模型中包含IFormFile

public class FormData {
    public int id { get; set; }
    public IFormFile fileToUpload { get; set; }
}

模型绑定器应该选择类型并使用传入数据填充模型。

更新控制器操作以接受模型并通过将内容复制到新请求来代理数据。

[Route("api/[controller]")]
public class DocumentController : Controller {
    // POST api/document
    [HttpPost]
    public async Task<IActionResult> Post(FormData formData) {
        if(formData != null && ModelState.IsValid) {
            client.BaseAddress = new Uri("http://example.com:8000");
            client.DefaultRequestHeaders.Accept.Clear();

            var multiContent = new MultipartFormDataContent();

            var file = formData.fileToUpload;
            if(file != null) {
                var fileStreamContent = new StreamContent(file.OpenReadStream());
                multiContent.Add(fileStreamContent, "fileToUpload", file.FileName);
            }

            multiContent.Add(new StringContent(formData.id.ToString()), "id");

            var response = await client.PostAsync("/document/upload", multiContent);
            if (response.IsSuccessStatusCode) {
               var retValue = await response.Content.ReadAsAsync<DocumentUploadResult>();
               return Ok(reyValue);
            }
        }
        //if we get this far something Failed.
        return BadRequest();
    }        
}

您可以根据需要包含必要的异常处理程序,但这是如何向前传递表单数据的最小示例。