繁体   English   中英

具有 HttpClientFactory 实现的动态代理

[英]Having dynamic proxy with HttpClientFactory implementation

我有Asp.Net Core WebApi 我正在根据HttpClientFactory 模式发出 Http 请求。 这是我的示例代码:

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddHttpClient<IMyInterface, MyService>();
    ...
}

public class MyService: IMyInterface
{
    private readonly HttpClient _client;

    public MyService(HttpClient client)
    {
        _client = client;
    }

    public async Task CallHttpEndpoint()
    {
        var request = new HttpRequestMessage(HttpMethod.Get, "www.customUrl.com");
        var response = await _client.SendAsync(request);
        ...
    }

}

我想通过动态代理实现发送请求。 这基本上意味着我可能需要为每个请求更改代理。 至于现在我发现了 2 个 approuces,其中没有一个对我来说似乎很好:

1.有一个像这样的静态代理:

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddHttpClient<IMyInterface, MyService>().ConfigurePrimaryHttpMessageHandler(() =>
        {
            return new HttpClientHandler
            {
                Proxy = new WebProxy("http://127.0.0.1:8888"),
                UseProxy = true
            };
        });
    ...
}

但是在这种方法中,每个服务只能有一个代理。

2.为每个请求处理HttpClient

    HttpClientHandler handler = new HttpClientHandler()
    {
        Proxy = new WebProxy("http://127.0.0.1:8888"),
        UseProxy = true,
    };

    using(var client = new HttpClient(handler))
    {
        var request = new HttpRequestMessage(HttpMethod.Get, "www.customUrl.com");
        var response = await client.SendAsync(request);
        ...
    }

但是这样我违反了 HttpClientFactory 模式,它可能会导致应用程序性能出现问题,如下 文所述

有没有第三种方法可以在不重新创建HttpClient情况下动态更改代理?

在实例化后,无法更改HttpClientHandler的任何属性或将新版本的HttpClientHandler分配给现有的HttpClient 因此,不可能为特定的HttpClient设置动态代理:您只能指定一个代理。

实现此目的的正确方法是使用命名客户端,并为每个代理端点定义一个客户端。 然后,您需要注入IHttpClientFactory并选择要使用的代理之一,请求实现该代理的命名客户端。

services.AddHttpClient("MyServiceProxy1").ConfigurePrimaryHttpMessageHandler(() =>
{
    return new HttpClientHandler
    {
        Proxy = new WebProxy("http://127.0.0.1:8888"),
        UseProxy = true
    };
});

services.AddHttpClient("MyServiceProxy2").ConfigurePrimaryHttpMessageHandler(() =>
{
    return new HttpClientHandler
    {
        Proxy = new WebProxy("http://127.0.0.1:8889"),
        UseProxy = true
    };
});

...

然后:

public class MyService : IMyInterface
{
    private readonly HttpClient _client;

    public MyService(IHttpClientFactory httpClientFactory)
    {
        _client = httpClientFactory.CreateClient("MyServiceProxy1");
    }

    public async Task CallHttpEndpoint()
    {
        var request = new HttpRequestMessage(HttpMethod.Get, "www.customUrl.com");
        var response = await _client.SendAsync(request);
        ...
    }
}

我可以通过从 HttpClientHandler 继承来做到这一点:

public class ProxyHttpHandler : HttpClientHandler
{
    private int currentProxyIndex = 0;

private ProxyOptions proxyOptions;

public ProxyHttpHandler(IOptions<ProxyOptions> options)
{
    proxyOptions = options != null ? options.Value : throw new ArgumentNullException(nameof(options));
    UseProxy = true;
}

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
    var proxy = proxyOptions.Proxies[currentProxyIndex];
    var proxyResolver = new WebProxy(proxy.Host, proxy.Port)
    {
        Credentials = proxy.Credentials
    };

    Proxy = proxyResolver;

    currentProxyIndex++;
    if(currentProxyIndex >= proxyOptions.Proxies.Count)
        currentProxyIndex = 0;

    return base.SendAsync(request, cancellationToken);
}

}

然后我在 IoC 中注册我的ProxyHttpHandlerProxyOptions

public IForksCoreConfigurationBuilder ConfigureProxy(Action<ProxyOptions> options)
{
    Services.AddOptions<ProxyOptions>().Configure(options);
    Services.AddTransient<ProxyHttpHandler>();
    Services.AddHttpClient<IService, MyService>()
            .ConfigurePrimaryHttpMessageHandler<ProxyHttpHandler>();

    return this;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM