给HttpClient添加动态代理

发布时间 2023-07-31 11:23:20作者: jesn
builder.Services.AddTransient<DynamicProxyHandler>();
builder.Services.AddHttpClient("searchIp", config =>
{
    
}).ConfigurePrimaryHttpMessageHandler(provider =>
{
    var proxyHandler = provider.GetRequiredService<DynamicProxyHandler>();
    return proxyHandler;
});
public class DynamicProxyHandler : HttpClientHandler
{
    private readonly IFreeProxyPoolAppService _freeProxyPoolAppService;

    public DynamicProxyHandler(IFreeProxyPoolAppService freeProxyPoolAppService)
    {
        _freeProxyPoolAppService = freeProxyPoolAppService;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        var maxRetryAttempts = 10;
        var retry = 0;

        HttpResponseMessage response = null;

        // 获取动态代理IP
        var proxyUrl = await _freeProxyPoolAppService.GetProxy();

        if (!string.IsNullOrEmpty(proxyUrl))
        {
            while (retry < maxRetryAttempts)
            {
                if (retry > 0)
                {
                    proxyUrl = await _freeProxyPoolAppService.GetProxy();
                }
                try
                {
                    using var httpClientHandler = new HttpClientHandler();
                    httpClientHandler.Proxy = new WebProxy(proxyUrl, BypassOnLocal: false);
                    using var httpClient = new HttpClient(httpClientHandler);
                    httpClient.Timeout = TimeSpan.FromSeconds(15);
                    var clonedRequest = await CloneHttpRequestMessage(request);
                    response = await httpClient.SendAsync(clonedRequest, cancellationToken);
                    break;
                }
                catch (TaskCanceledException ex) when (!cancellationToken.IsCancellationRequested)
                {
                    // request 请求超时
                    retry++;
                }
                catch (HttpRequestException ex)
                {
                    Console.WriteLine(ex.Message);
                    Console.WriteLine($"重试次数:{retry++}");
                    retry++;
                }
            }
        }
        else
        {
            using var httpClient = new HttpClient();
            var clonedRequest = await CloneHttpRequestMessage(request);
            response = await httpClient.SendAsync(clonedRequest, cancellationToken);
        }
        return response;
    }
    
    private async Task<HttpRequestMessage> CloneHttpRequestMessage(HttpRequestMessage request)
    {
        var clonedRequest = new HttpRequestMessage(request.Method, request.RequestUri);

        // Copy the request content (if any)
        if (request.Content != null)
        {
            clonedRequest.Content = new StreamContent(await request.Content.ReadAsStreamAsync());
            if (request.Content.Headers != null)
            {
                foreach (var header in request.Content.Headers)
                {
                    clonedRequest.Content.Headers.TryAddWithoutValidation(header.Key, header.Value);
                }
            }
        }

        // Copy the request headers
        foreach (var header in request.Headers)
        {
            clonedRequest.Headers.TryAddWithoutValidation(header.Key, header.Value);
        }

        return clonedRequest;
    }
}