时间:2019-03-17 标签:c#HttpClientwithproxy

Ole*_*nko 7 c# proxy httpclient

我对某些资源执行了很多请求HttpClient。为了避免舔,我将其用作单个实例。类似的东西......我想使用代理,那么如何为每个请求使用不同的代理?

谢谢!

public class Program
{
    private static HttpClient Client = new HttpClient();
    public static void Main(string[] args)
    {
        Console.WriteLine("Starting connections");
        for(int i = 0; i<10; i++)
        {
            var result = Client.GetAsync("http://aspnetmonsters.com").Result;
            Console.WriteLine(result.StatusCode);
        }
        Console.WriteLine("Connections done");
        Console.ReadLine();
    }

}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ger 5

啊,我看错问题了。
它不是关于如何将随机 IWebProxy 与 HttpClientHandler 一起使用,而是如何解决在第一个请求开始后无法重置同一 HttpClientHandler 的代理属性的问题。

问题是您无法重置 HttpClientHandler 的代理...

System.InvalidOperationException: '此实例已启动一个或多个请求。
只能在发送第一个请求之前修改属性。

但这仍然相当容易。

  • HttpClientHandler 的 Proxy 属性采用一个实现 IWebProxy 的对象。
  • IWebProxy 接口有一个 GetProxy 方法,它返回代理的 Uri。
  • 因此,您可以创建自己的类来实现此接口,并控制它如何使用 GetProxy 返回代理的 Uri。
  • 您可以让它包装另一个 IWebProxy,并且在 GetProxy 中它将返回内部 IWebProxy 的 GetProxy。
  • 这样,您就不必更改 HttpClientHandler 的 Proxy 属性,只需更改内部 IWebProxy 即可。

执行:

public class WebProxyService
  : System.Net.IWebProxy
{
    protected System.Net.IWebProxy m_proxy;


    public System.Net.IWebProxy Proxy
    {
        get { return this.m_proxy ??= System.Net.WebRequest.DefaultWebProxy; }
        set { this.m_proxy = value; }
    }

    System.Net.ICredentials System.Net.IWebProxy.Credentials
    {
        get { return this.Proxy.Credentials; }
        set { this.Proxy.Credentials = value; }
    }


    public WebProxyService()
    { } // Constructor 

    public WebProxyService(System.Net.IWebProxy proxy)
    {
        this.Proxy = proxy;
    } // Constructor 


    System.Uri System.Net.IWebProxy.GetProxy(System.Uri destination)
    {
        return this.Proxy.GetProxy(destination);
    }

    bool System.Net.IWebProxy.IsBypassed(System.Uri host)
    {
        return this.Proxy.IsBypassed(host);
    }


}
Run Code Online (Sandbox Code Playgroud)

然后用法如下:

public class AlternatingProxy 
{


    public static async System.Threading.Tasks.Task Test()
    {
        string url = "http://aspnetmonsters.com";
       
        System.Net.WebProxy[] proxies = new[] {
            null,
            new System.Net.WebProxy("104.238.172.20", 8080),
            new System.Net.WebProxy("104.238.167.193", 8080),
            new System.Net.WebProxy("136.244.102.38", 8080),
            new System.Net.WebProxy("95.179.202.40", 8080)
        };

        System.Random rnd = new System.Random();
        WebProxyService proxyService = new WebProxyService();
        
        using (System.Net.Http.HttpClient hc = new System.Net.Http.HttpClient(
          new System.Net.Http.HttpClientHandler { UseProxy = true, Proxy = proxyService }
          ))
        {
            // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent
            hc.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148");
            hc.DefaultRequestHeaders.Add("Accept-Language", "fr-FR, fr;q=0.9, en;q=0.8, it;q=0.7, *;q=0.5");
            hc.DefaultRequestHeaders.Add("Referer", "https://www.baidu.com");
            hc.DefaultRequestHeaders.ConnectionClose = true; 

            for (int i = 0; i < 10; ++i)
            {
                proxyService.Proxy = proxies[rnd.Next(proxies.Length)];
                string response = await hc.GetStringAsync(url);
            }
        }

    } // End Task Test  


} // End Class TestMe 
Run Code Online (Sandbox Code Playgroud)

编辑:

如果你想使用单例,也许这是一个想法:

公共类WebProxyService:System.Net.IWebProxy {

    protected System.Net.IWebProxy m_proxy;


    public System.Net.IWebProxy Proxy
    {
        get { return this.m_proxy ??= System.Net.WebRequest.DefaultWebProxy; }
        set { this.m_proxy = value; }
    }

    System.Net.ICredentials System.Net.IWebProxy.Credentials
    {
        get { return this.Proxy.Credentials; }
        set { this.Proxy.Credentials = value; }
    }


    public WebProxyService()
    { } // Constructor 


    public WebProxyService(System.Net.IWebProxy proxy)
    {
        this.Proxy = proxy;
    } // Constructor 


    protected System.Func<System.Net.WebProxy>[] proxies = new System.Func<System.Net.WebProxy>[] {
            delegate(){ return new System.Net.WebProxy("104.238.172.20", 8080); },
            delegate (){ return new System.Net.WebProxy("104.238.167.193", 8080);},
            delegate(){ return new System.Net.WebProxy("136.244.102.38", 8080);},
            delegate(){ return new System.Net.WebProxy("95.179.202.40", 8080);}
        };


    System.Uri System.Net.IWebProxy.GetProxy(System.Uri destination)
    {
        return proxies[RandomGen2.Next(proxies.Length)]().GetProxy(destination);
    }


    bool System.Net.IWebProxy.IsBypassed(System.Uri host)
    {
        return this.Proxy.IsBypassed(host);
    }



    private static class RandomGen2
    {
        private static System.Random _global = new System.Random();

        [System.ThreadStatic]
        private static System.Random _local;

        public static int Next(int maxValue)
        {
            System.Random inst = _local;
            if (inst == null)
            {
                int seed;
                lock (_global) seed = _global.Next();
                _local = inst = new System.Random(seed);
            }
            return inst.Next(maxValue);
        }
    }


} // End Class WebProxyService 
Run Code Online (Sandbox Code Playgroud)

编辑2:

如果更改代理,它仍然不是线程安全的。
因此,使用固定的不可变代理列表并阻止设置属性。
这样,它应该是线程安全的。

public class WebProxyService
      : System.Net.IWebProxy
{


    protected System.Net.IWebProxy[] m_proxyList;

    public System.Net.IWebProxy Proxy
    {
        get
        {
            // https://devblogs.microsoft.com/pfxteam/getting-random-numbers-in-a-thread-safe-way/
            if (this.m_proxyList != null)
                return this.m_proxyList[ThreadSafeRandom.Next(this.m_proxyList.Length)];
            
            return System.Net.WebRequest.DefaultWebProxy;
        }
        set
        {
            throw new System.InvalidOperationException("It is not thread-safe to change the proxy-list.");
        }
    }

    System.Net.ICredentials System.Net.IWebProxy.Credentials
    {
        get { return this.Proxy.Credentials; }
        set { this.Proxy.Credentials = value; }
    }


    public WebProxyService()
    {
    } // Constructor 


    public WebProxyService(System.Net.IWebProxy[] proxyList)
    {
        this.m_proxyList = proxyList;
    } // Constructor 


    System.Uri System.Net.IWebProxy.GetProxy(System.Uri destination)
    {
        return this.Proxy.GetProxy(destination);
    }


    bool System.Net.IWebProxy.IsBypassed(System.Uri host)
    {
        return this.Proxy.IsBypassed(host);
    }


} // End Class WebProxyService 
Run Code Online (Sandbox Code Playgroud)
旧答案:----

在 ASP.NET-Core 中使用 HttpClient 代理实际上非常简单。
您需要做的就是在 HttpClient 构造函数中设置处理程序。
然后为每个请求设置处理程序的代理属性。
像这样:

public class Program
{

    public static async System.Threading.Tasks.Task Main(string[] args)
    {
        string url = "http://aspnetmonsters.com";
        System.Net.WebProxy[] proxies = new[] {
            null,
            new System.Net.WebProxy("104.238.172.20", 8080),
            new System.Net.WebProxy("104.238.167.193", 8080),
            new System.Net.WebProxy("136.244.102.38", 8080),
            new System.Net.WebProxy("95.179.202.40", 8080)
        };

        System.Random rnd = new System.Random();
        using (System.Net.Http.HttpClientHandler handler = new System.Net.Http.HttpClientHandler()
        {
            Proxy = new System.Net.WebProxy("http://127.0.0.1:8888"),
            UseProxy = true,
        })
        {

            using (System.Net.Http.HttpClient hc = new System.Net.Http.HttpClient(handler))
            {
                System.Console.WriteLine("Starting connections");
                for (int i = 0; i < 10; i++)
                {
                    handler.Proxy = proxies[rnd.Next(proxies.Length)];
                    await hc.GetAsync(url);

                    // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent
                    hc.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148");
                    hc.DefaultRequestHeaders.Add("Accept-Language", "fr-FR, fr;q=0.9, en;q=0.8, it;q=0.7, *;q=0.5");
                    hc.DefaultRequestHeaders.Add("Referer", "https://www.baidu.com");

                    using (System.Net.Http.HttpResponseMessage response = await hc.GetAsync(url))
                    {
                        // using (var fs = new System.IO.MemoryStream())
                        // { await response.Content.CopyToAsync(fs); }
                        byte[] ba = await response.Content.ReadAsByteArrayAsync();

                    } // End Using response 

                } // Next i 

                System.Console.WriteLine("Ending connections");
            } // End Using hc 

        } // End Using handler 

        System.Console.WriteLine("--- Press any key to continue --- ");
        System.Console.ReadKey();
    } // End Task Main 

} // End Class Program 
Run Code Online (Sandbox Code Playgroud)


Nic*_*los -1

因此,基本上,为了能够更改代理,您将需要HttpClientHandler.
可以在这里找到一个简单的示例:C# use proxy with HttpClient request
和另一个示例:Simple C# .NET 4.5 HTTPClient Request using Basic Auth and Proxy

我建议将其保留HttpClientHandler在私有字段中,并在每次需要时使用引用来更改代理。
但请记住,如果您需要同时使用不同的代理,则需要拥有该类的多个实例HttpClientHandler

如果您需要我为此制作示例代码。平我。

谢谢。