C# 从WebAPI调用HttpClient时更改请求URI

C# 从WebAPI调用HttpClient时更改请求URI,c#,asp.net-web-api,dotnet-httpclient,C#,Asp.net Web Api,Dotnet Httpclient,我正在为希望与另一台服务器上的API通信的ASP.NET MVC应用程序实现一个透明的服务器端代理;代码相当简单: public class TransparentProxyDelegatingHandler : DelegatingHandler { private static readonly Uri ApiUri; private static readonly HttpClient Client; static TransparentProxyDelegati

我正在为希望与另一台服务器上的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;
    }
}
公共类透明Proxy DelegatingHandler:DelegatingHandler
{
私有静态只读Uri;
私有静态只读HttpClient客户端;
静态透明Proxy DelegatingHandler()
{
var apiServer=新Uri(ConfigurationManager.AppSettings[“apirl”]);
ApiUri=新的Uri(apiServer);
Client=新的HttpClient();
}
受保护的覆盖异步任务SendAsync(HttpRequestMessage请求,CancellationToken CancellationToken)
{
Add(“X-Forwarded-For”,request.GetClientIpAddress());
request.RequestUri=TranslateIncomingRequestToUpstreamApi(请求);
request.Headers.AcceptEncoding.Clear();
var response=wait Client.sendaync(请求,HttpCompletionOption.ResponseHeadersRead,cancellationToken);
返回响应;
}
私有静态Uri TranslateIncomingRequestToUpstreamApi(HttpRequestMessage请求)
{
var forwardUri=新的UriBuilder(request.RequestUri)
{
Host=ApiUri.Host,
Path=request.RequestUri.AbsolutePath.Replace(“/Proxy”,string.Empty)
};
返回forwardUri.Uri;
}
}
所以如果我查询
GEThttps://ui.myserver.com/proxy/timesheets?from=2018-01-01
,代理将请求URI更改为
GEThttps://api.myserver.com/timesheets?from=2018-01-01
,我可以在调试器中验证这一点;但是,当调用
SendAsync
方法时,请求URI的主机名部分会更改回
https://ui.myserver.com
,则调用失败


当我调用
SendAsync
时,它为什么要更改
request.RequestUri
的值?我已经在GitHub()中检查了源代码,但是更改值的条件似乎都不适用于我的情况。不幸的是,GitHub源代码与调试符号不一致,因此我似乎无法进入
HttpClient
源代码以了解到底发生了什么。

好的,我找到了问题的原因;我需要设置更改主机头;对代理的初始请求将其设置为UI的主机名(UI.myserver.com),这将覆盖在请求中设置的代理的主机名。因此,如果我添加以下内容:

request.Headers.Host = $"{ApiUri.Host}:{ApiUri.Port}";
然后一切都神奇地运转起来