我正在为要与另一台服务器上的API通信的ASP.NET MVC应用程序实现透明的服务器端代理。该代码非常简单:
public class TransparentProxyDelegatingHandler : DelegatingHandler
{
private static readonly Uri ApiUri;
private static readonly HttpClient Client;
static TransparentProxyDelegatingHandler()
{
var apiServer = new Uri(ConfigurationManager.AppSettings["ApiUrl"]);
ApiUri = new Uri(apiServer);
Client = new HttpClient();
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("X-Forwarded-For", request.GetClientIpAddress());
request.RequestUri = TranslateIncomingRequestToUpstreamApi(request);
request.Headers.AcceptEncoding.Clear();
var response = await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
return response;
}
private static Uri TranslateIncomingRequestToUpstreamApi(HttpRequestMessage request)
{
var forwardUri = new UriBuilder(request.RequestUri)
{
Host = ApiUri.Host,
Path = request.RequestUri.AbsolutePath.Replace("/Proxy", string.Empty)
};
return forwardUri.Uri;
}
}
因此,如果我查询GET https://ui.myserver.com/proxy/timesheets?from=2018-01-01
,则代理将请求URI更改为GET https://api.myserver.com/timesheets?from=2018-01-01
,然后可以在调试器中进行验证;但是,当调用SendAsync
方法时,请求URI的主机名部分将改回https://ui.myserver.com
,并且调用失败。
为什么我调用request.RequestUri
时会更改SendAsync
的值?我已经在GitHub(https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/HttpClient.cs)中检查了源代码,但是更改值的条件似乎都不适用于我的情况。不幸的是,GitHub源代码与调试符号不符,因此我似乎无法进入HttpClient
源代码来了解实际情况。
答案 0 :(得分:1)
好的,我找到了问题的原因;我需要设置更改Host标头;对代理的初始请求将其设置为UI的主机名(ui.myserver.com),并且该请求将覆盖在请求中设置的代理的主机名。因此,如果我添加以下内容:
request.Headers.Host = $"{ApiUri.Host}:{ApiUri.Port}";
然后一切都神奇地起作用。