繁体   English   中英

c# HttpClient 带代理

[英]c# HttpClient with proxy

我使用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();
    }

}

您将需要实现 IWebProxy。

这是一个非常行的示例。

首先实现 IWebProxy

public class MyProxy : IWebProxy {
public MyProxy() {  credentials = new NetworkCredential( user, password ); }
private NetworkCredential credentials;
public ICredentials Credentials
{
    get = > credentials;
    set = > throw new NotImplementedException();
}
private Uri proxyUri;
public Uri GetProxy( Uri destination )
{
    return proxyUri; // your proxy Uri
}
public bool IsBypassed( Uri host )
{
    return false;
}
private const string user = "yourusername";
private const string password = "password";}

然后将其提供给 HttpClient 中的处理程序

public class MyHttpClient {
internal static HttpResult httpMethod( ... )
{
    var _client = client();
    try
    {
        var message = new HttpRequestMessage( method, url );
        message.Content = new StringContent( content, Encoding.UTF8, "application/json" );
        var result = _client.SendAsync( message ).Result;// handle result
    }
    catch( Exception e ){}
}
private static HttpClient client()
{
    var httpClientHandler = new HttpClientHandler() { Proxy = new MyProxy() };
    var httpClient = new MyClient( new Uri( "baseurl" ), httpClientHandler );
    return httpClient;

啊,我看错了这个问题。
这不是关于如何将随机 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);
    }


}

然后用法是这样的:

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 

编辑:

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

公共类 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 

编辑2:

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

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 

老答案:----

在 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

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

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

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

谢谢你。

暂无
暂无

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

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