如何在.net Core MVC控制器中返回HttpResponseMessage而不将其序列化为JSON?

问题描述

我正在研究一种使用ASP.Net Core MVC项目类型的Web代理模式。我想基本上将HttpRequestMessage传递给控制器​​中的httpClient,然后向远程网站(例如https://www.abc.fake)发出请求,然后返回完全从客户端返回的响应(正文和标头) 。示例代码

    [Microsoft.AspNetCore.Mvc.Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    //[HttpGet]
    public async Task<HttpResponseMessage> Get()
    {
        var httpClient = new HttpClient();
        
         var resp = await httpClient.GetAsync("https://www.abc.fake");

        return resp;
        
    }
}

问题是,每次执行此操作时,我只会得到响应消息的JSON序列化版本。它实际上并没有发送回我从远程网站获得的HTML。这就是我所看到的:

{"version":{"major":1,"minor":1,"build":-1,"revision":-1,"majorRevision":-1,"minorRevision":-1},"content":{"headers":[{"Key":"Content-Type","Value":["text/html; charset=utf-8"]},{"Key":"Content-Length","Value":["1036119"]},{"Key":"Expires","Value":["Wed,23 Sep 2020 21:44:35 GMT"]},{"Key":"Last-Modified",23 Sep 2020 21:44:35 GMT"]}]},"statusCode":200,"reasonPhrase":"OK","headers":[{"Key":"Connection","Value":["keep-alive"]},{"Key":"vary","Value":["Accept-Encoding","Accept-Encoding"]},{"Key":"Date",23 Sep 2020 21:41:54 GMT"]},{"Key":"Server","Value":["Nginx/1.16.1"]},{"Key":"Via","Value":["1.1 varnish-v4","1.1 e8afb729a4bc6f5676d32307ea14bdae.cloudfront.fake (CloudFront)"]},{"Key":"Accept-Ranges","Value":["bytes"]},{"Key":"Cache-Control","Value":["must-revalidate,max-age=0"]},{"Key":"Set-Cookie","Value":["SWID=0C8B6C96-3F05-43D5-C3D1-2676E1C15F8C; path=/; Expires=Sun,23 Sep 2040 21:41:54 GMT; domain=abc.fake;"]},{"Key":"X-Cache","Value":["Miss from cloudfront"]},{"Key":"X-Amz-Cf-Pop","Value":["HIO50-C1"]},{"Key":"X-Amz-Cf-Id","Value":["yKz-d9KhZdb-5qdDpppD0jeFqYHfFQA4Z1RT98Nk31eaH7kB_FXisQ=="]}],"trailingHeaders":[],"requestMessage":{"version":{"major":1,"content":null,"method":{"method":"GET"},"requestUri":"https://abc.fake/","headers":[{"Key":"Request-Id","Value":["|8e9d36f9-4b9e69ca8ec31ee9.1."]}],"properties":{}},"isSuccessstatusCode":true}

解决方法

在链接到@ tym32167指向我的AspNetCore.Proxy nuget软件包之后;我可以验证我想要的。对于任何想这样做的人,基本上就是这么简单:

[Route("{*everything}")]
public async Task Get()
{
    var host = Request.Host.Host;
    string path = Request.Path;
    string queryString = null;
    if (Request.QueryString != null)
    {
        var queryStringBuilder = new StringBuilder();
        var isFirstParameter = true;
        foreach (var parameter in Request.Query)
        {
            var leadingCharacter = isFirstParameter ? "?" : "&";
            queryStringBuilder.Append($"{leadingCharacter}{parameter.Key}={parameter.Value}");
            isFirstParameter = false;
        }
        queryString = queryStringBuilder.ToString();
    }
    var requestUrl = $"{Request.Scheme}://{host}{path}{queryString}";
    var b = HttpProxyOptionsBuilder.Instance.New();
    b.WithHttpClientName("default");
    b.WithShouldAddForwardedHeaders(true);
    var options = b.Build();         
    await this.HttpProxyAsync(requestUrl,options);
}
,

我参加这个聚会有点晚了,但值得一提的是,这种映射在现有 Web API 代码库之间的互操作过渡到 ASP.NET Core 的早期非常普遍。它不再维护,但有一个由 ASP.NET 团队编写的 Web API Shim 库来支持转换。在该存储库中,您可以获取 2 个关键文件:

要连接它,您只需要像这样添加输出格式化程序:

mvcOptions.OutputFormatters.Insert(0,new HttpResponseMessageOutputFormatter());

使用方式与在 Web API 模型中的使用方式相同,如下所示:

[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    readonly IHttpClientFactory factory;

    public WeatherForecastController(IHttpClientFactory factory) => this.factory = factory;

    [HttpGet]
    public async Task<IActionResult> Get(CancellationToken cancellationToken)
    {
        using var client = factory.CreateClient("WeatherChannel");
        var response = await client.GetAsync("https://weather.com/",cancellationToken);
        return new ResponseMessageResult(response);
    }
}

既然您提到要创建代理,您还可以从传入的 HttpRequest 构建一个 HttpRequestMesage,如果您需要将其转发到 HttpClient。代码有点复杂,但您可以从 WebApiCompatShim 源中获得所需的一切。

,

尝试这样的事情

public async Task<IActionResult> Get()
{
     HttpClient httpClient = new HttpClient();
     var resp = httpClient.GetAsync("https://www.abc.fake").GetAwaiter().GetResult();
     if (!resp.IsSuccessStatusCode)
         return BadRequest();

     return resp.Content;
    
}