我正在研究一种使用ASP.Net Core MVC项目类型的web代理模式。我想基本上把HttpRequestMessage传递给控制器中的httpClient,然后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","Value":["Wed, 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","Value":["Wed, 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,"minor":1,"build":-1,"revision":-1,"majorRevision":-1,"minorRevision":-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);
}
我来晚了一点,但值得一提的是,这种映射在早期非常常见,用于在过渡到ASP.NET Core的现有Web API代码库之间进行互操作。它不再维护,但有一个Web API Shim库由ASP.NET团队编写以支持转换。在该回购中,有两个关键文件可以获取:
- HttpResponseMessageOutputFormatter.cs
- 响应消息结果.cs
要连接它,您只需要添加这样的输出格式化程序:
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);
}
}
由于您提到您正在创建一个代理,如果您需要将其转发到HttpClient,您还可以从传入的HttpRequest构建HTTP请求Mesage。代码有点复杂,但您可以从WebApiCompatShem源代码中获得所需的一切。
试试这样的
public async Task<IActionResult> Get()
{
HttpClient httpClient = new HttpClient();
var resp = await httpClient.GetAsync("https://www.abc.fake");
if (!resp.IsSuccessStatusCode)
return BadRequest();
return resp.Content;
}