Configurar um proxy para requisições HTTP em C# com HttpClient envolve instanciar um HttpClientHandler, atribuir à sua propriedade Proxy um objeto WebProxy com o endereço do proxy e credenciais opcionais e, então, passar esse handler configurado para o construtor do HttpClient. Essa configuração permite que aplicações roteiem o tráfego web de saída por um servidor intermediário, o que é essencial para segurança de rede, controle de acesso, logging ou para contornar restrições geográficas.
Entendendo HttpClient, HttpClientHandler e WebProxy
HttpClient é a classe principal do .NET para enviar requisições HTTP e receber respostas HTTP. Ela foi projetada para instâncias de vida longa e requisições concorrentes.
HttpClientHandler é o message handler subjacente que o HttpClient usa para enviar requisições. Ele oferece opções de configuração de rede, incluindo configuração de proxy, credenciais e ajustes de SSL/TLS.
WebProxy é uma classe que especifica a URI de um servidor proxy e permite configurar listas de bypass e credenciais.
Gerenciamento de instâncias de HttpClient
Instâncias de HttpClient devem, em geral, ser reutilizadas entre várias requisições para evitar problemas de esgotamento de sockets. Criar um novo HttpClient para cada requisição pode causar problemas de desempenho e esgotamento de recursos. Um padrão comum é usar uma única instância de HttpClient durante todo o ciclo de vida da aplicação ou aproveitar o IHttpClientFactory em aplicações ASP.NET Core.
Configuração básica de proxy
Para configurar um proxy HTTP ou HTTPS básico, crie uma instância de HttpClientHandler, defina sua propriedade Proxy como um novo objeto WebProxy inicializado com a URI do proxy e passe esse handler para o construtor do HttpClient.
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
public class ProxySetup
{
public static async Task Main(string[] args)
{
string proxyAddress = "http://your.proxy.server:8080"; // Substitua pelo endereço do seu proxy
string targetUrl = "http://httpbin.org/get"; // Um endpoint público para teste
// Cria uma instância de WebProxy
var webProxy = new WebProxy(proxyAddress, BypassOnLocal: false);
// Cria um HttpClientHandler e atribui o WebProxy
var handler = new HttpClientHandler
{
Proxy = webProxy,
UseProxy = true // Habilita explicitamente o uso do proxy
};
// Cria um HttpClient com o handler configurado
using (var httpClient = new HttpClient(handler))
{
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode(); // Lança exceção se o código de status HTTP for de erro
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Request successful. Response snippet:");
Console.WriteLine(responseBody.Substring(0, Math.Min(responseBody.Length, 500))); // Imprime os primeiros 500 caracteres
}
catch (HttpRequestException e)
{
Console.WriteLine($"Request error: {e.Message}");
}
catch (WebException e)
{
Console.WriteLine($"Proxy or network error: {e.Message}");
}
}
}
}
Neste exemplo:
* WebProxy(proxyAddress, BypassOnLocal: false) cria um objeto de proxy. BypassOnLocal: false garante que as requisições a endereços locais (por exemplo, localhost) também passem pelo proxy, a menos que sejam explicitamente ignoradas depois.
* handler.UseProxy = true instrui explicitamente o handler a usar o proxy configurado.
Proxy com autenticação
Se o servidor proxy exigir autenticação (por exemplo, usuário e senha), defina a propriedade Credentials do objeto WebProxy usando uma instância de NetworkCredential.
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
public class AuthenticatedProxySetup
{
public static async Task Main(string[] args)
{
string proxyAddress = "http://your.authenticated.proxy.server:8080"; // Substitua
string proxyUsername = "your_username"; // Substitua
string proxyPassword = "your_password"; // Substitua
string targetUrl = "http://httpbin.org/get";
var credentials = new NetworkCredential(proxyUsername, proxyPassword);
var webProxy = new WebProxy(proxyAddress, BypassOnLocal: false)
{
Credentials = credentials
};
var handler = new HttpClientHandler
{
Proxy = webProxy,
UseProxy = true
};
using (var httpClient = new HttpClient(handler))
{
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Request successful with authenticated proxy.");
Console.WriteLine(responseBody.Substring(0, Math.Min(responseBody.Length, 500)));
}
catch (HttpRequestException e)
{
Console.WriteLine($"Request error: {e.Message}");
}
catch (WebException e)
{
Console.WriteLine($"Proxy or network error: {e.Message}");
}
}
}
}
Usando o proxy padrão do sistema
O HttpClientHandler pode ser configurado para usar as configurações de proxy padrão do sistema, normalmente definidas no sistema operacional ou nas configurações do Internet Explorer. Esse costuma ser o comportamento desejado em ambientes corporativos.
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class SystemDefaultProxySetup
{
public static async Task Main(string[] args)
{
string targetUrl = "http://httpbin.org/get";
var handler = new HttpClientHandler
{
UseSystemProxy = true // Usa as configurações de proxy padrão do sistema
};
using (var httpClient = new HttpClient(handler))
{
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Request successful using system default proxy.");
Console.WriteLine(responseBody.Substring(0, Math.Min(responseBody.Length, 500)));
}
catch (HttpRequestException e)
{
Console.WriteLine($"Request error: {e.Message}");
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
}
}
Definir UseSystemProxy = true configura automaticamente o HttpClientHandler para descobrir e usar as configurações de proxy definidas no nível do sistema operacional. Se UseSystemProxy for true, a propriedade Proxy é ignorada.
Ignorando o proxy para endereços específicos
A classe WebProxy oferece mecanismos para ignorar o proxy em determinados endereços.
BypassProxyOnLocal
Definir BypassProxyOnLocal = true no construtor ou na propriedade do WebProxy faz com que o proxy não seja usado para recursos da intranet local. Isso costuma ser desejável para evitar que o tráfego interno seja roteado desnecessariamente por um proxy externo.
var webProxy = new WebProxy("http://your.proxy.server:8080")
{
BypassProxyOnLocal = true // Não usar proxy para endereços locais
};
BypassList
Para um controle mais granular, a propriedade BypassList permite especificar um array de expressões regulares que definem as URIs para as quais o proxy deve ser ignorado.
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
public class ProxyBypassListSetup
{
public static async Task Main(string[] args)
{
string proxyAddress = "http://your.proxy.server:8080";
string targetUrl = "http://internal.api.com/data"; // Exemplo de URL interna
string externalUrl = "http://external.api.com/data"; // Exemplo de URL externa
// Define uma lista de bypass usando expressões regulares
string[] bypassList = new string[]
{
"internal\\.api\\.com", // Bypass para internal.api.com
"\\.local$" // Bypass para qualquer host terminado em .local
};
var webProxy = new WebProxy(proxyAddress)
{
BypassList = bypassList,
BypassProxyOnLocal = false // Trate o bypass local via BypassList, se necessário
};
var handler = new HttpClientHandler
{
Proxy = webProxy,
UseProxy = true
};
using (var httpClient = new HttpClient(handler))
{
Console.WriteLine($"Attempting request to {targetUrl} (should bypass proxy)...");
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode();
Console.WriteLine($"Request to {targetUrl} successful. (Check proxy logs if available)");
}
catch (HttpRequestException e)
{
Console.WriteLine($"Request to {targetUrl} error: {e.Message}");
}
Console.WriteLine($"\nAttempting request to {externalUrl} (should use proxy)...");
try
{
HttpResponseMessage response = await httpClient.GetAsync(externalUrl);
response.EnsureSuccessStatusCode();
Console.WriteLine($"Request to {externalUrl} successful. (Check proxy logs if available)");
}
catch (HttpRequestException e)
{
Console.WriteLine($"Request to {externalUrl} error: {e.Message}");
}
}
}
}
HttpClientHandler vs. SocketsHttpHandler
O .NET Core 2.1 introduziu o SocketsHttpHandler como handler padrão do HttpClient, oferecendo melhor desempenho e consistência entre plataformas. O HttpClientHandler ainda existe e pode ser usado explicitamente, mas o SocketsHttpHandler é geralmente preferido em novos desenvolvimentos. Ao usar o SocketsHttpHandler, a configuração de proxy é ligeiramente diferente.
| Recurso | HttpClientHandler |
SocketsHttpHandler (recomendado para .NET Core/.NET 5+) |
|---|---|---|
| Tipo de proxy | WebProxy |
IWebProxy (geralmente WebProxy ou implementação personalizada) |
| Configuração | Defina a propriedade Proxy com uma instância de WebProxy. |
Defina a propriedade Proxy com uma instância de IWebProxy. |
| Proxy do sistema | UseSystemProxy = true |
UseProxy = true e Proxy = WebRequest.DefaultWebProxy ou null para o padrão do sistema. |
| Autenticação | WebProxy.Credentials |
WebProxy.Credentials (se WebProxy for usado) |
| Proxy SOCKS | Não suportado diretamente. | Suporte direto a SOCKS5 definindo a propriedade Proxy como new WebProxy("socks5://...") |
| Padrão no .NET | Padrão no .NET Framework. | Padrão no .NET Core 2.1+ / .NET 5+. |
Configurando o proxy com SocketsHttpHandler
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
public class SocketsHttpHandlerProxySetup
{
public static async Task Main(string[] args)
{
string proxyAddress = "http://your.proxy.server:8080";
string targetUrl = "http://httpbin.org/get";
var webProxy = new WebProxy(proxyAddress);
// SocketsHttpHandler é o padrão no .NET moderno, mas pode ser usado explicitamente
var handler = new SocketsHttpHandler
{
Proxy = webProxy, // Atribui a instância de IWebProxy
UseProxy = true, // Habilita explicitamente o uso do proxy
AllowAutoRedirect = true, // Exemplo de outras propriedades do SocketsHttpHandler
PooledConnectionLifetime = TimeSpan.FromMinutes(5)
};
using (var httpClient = new HttpClient(handler))
{
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Request successful using SocketsHttpHandler.");
Console.WriteLine(responseBody.Substring(0, Math.Min(responseBody.Length, 500)));
}
catch (HttpRequestException e)
{
Console.WriteLine($"Request error: {e.Message}");
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
}
}
Para usar o proxy padrão do sistema com SocketsHttpHandler, defina UseProxy = true e Proxy = WebRequest.DefaultWebProxy. Se Proxy for null e UseProxy for true, o SocketsHttpHandler tentará usar o proxy padrão do sistema.
Tratamento de erros e depuração
Ao encontrar problemas com a configuração de proxy, considere o seguinte:
* Conectividade de rede: verifique se o host da aplicação consegue alcançar o servidor proxy.
* Status do servidor proxy: confirme que o servidor proxy está operacional e corretamente configurado.
* Autenticação: revise as credenciais do proxy. Credenciais incorretas costumam resultar em erros HTTP 407 Proxy Authentication Required.
* Regras de firewall: verifique as regras de firewall locais e de rede que possam bloquear o tráfego de ou para o proxy.
* Logs do proxy: se houver acesso aos logs do servidor proxy, inspecione-os em busca de tentativas de conexão e erros.
* Exceções: capture HttpRequestException e WebException (para HttpClientHandler no .NET Framework) para obter mensagens de erro detalhadas.
Considerações de segurança
- Confiança: roteie o tráfego apenas por servidores proxy confiáveis. Proxies maliciosos podem interceptar, modificar ou registrar dados sensíveis.
- Credenciais: armazene as credenciais do proxy com segurança, evitando escrevê-las diretamente no código-fonte. Use variáveis de ambiente, arquivos de configuração ou serviços de gerenciamento de segredos.
- SSL/TLS: garanta que o proxy trate corretamente o tráfego SSL/TLS. Se o proxy fizer inspeção SSL (Man-in-the-Middle), a aplicação pode precisar confiar em uma autoridade certificadora raiz adicional. O
HttpClientHandlertem a propriedadeServerCertificateCustomValidationCallbackpara validação personalizada de certificados, mas ela deve ser usada com cautela.
