Configurar un proxy para solicitudes HTTP en C# con HttpClient implica instanciar un HttpClientHandler, asignar un objeto WebProxy con la dirección del proxy y credenciales opcionales a su propiedad Proxy, y luego pasar este controlador configurado al constructor de HttpClient. Esta configuración permite a las aplicaciones enrutar el tráfico web saliente a través de un servidor intermediario, lo cual es esencial para la seguridad de la red, el control de acceso, el registro o la elusión de restricciones geográficas.
Entendiendo HttpClient, HttpClientHandler y WebProxy
HttpClient es la clase principal en .NET para enviar solicitudes HTTP y recibir respuestas HTTP. Está diseñada para instancias de larga duración y solicitudes concurrentes.
HttpClientHandler es el controlador de mensajes subyacente que HttpClient utiliza para enviar solicitudes. Proporciona opciones de configuración para la configuración de red, incluida la configuración de proxy, credenciales y configuración SSL/TLS.
WebProxy es una clase que especifica la URI de un servidor proxy y permite la configuración de listas de omisión de proxy y credenciales.
Gestión de instancias de HttpClient
Las instancias de HttpClient generalmente deben reutilizarse en múltiples solicitudes para evitar problemas de agotamiento de sockets. Crear un nuevo HttpClient para cada solicitud puede provocar problemas de rendimiento y agotamiento de recursos. Un patrón común es usar una única instancia de HttpClient durante la vida útil de la aplicación o aprovechar IHttpClientFactory en aplicaciones ASP.NET Core.
Configuración básica del proxy
Para configurar un proxy HTTP o HTTPS básico, cree una instancia de HttpClientHandler, establezca su propiedad Proxy en un nuevo objeto WebProxy inicializado con la URI del proxy, y luego pase este controlador al constructor de 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"; // Reemplazar con la dirección de su proxy
string targetUrl = "http://httpbin.org/get"; // Un endpoint público para probar
// Crear una instancia de WebProxy
var webProxy = new WebProxy(proxyAddress, BypassOnLocal: false);
// Crear un HttpClientHandler y asignar el WebProxy
var handler = new HttpClientHandler
{
Proxy = webProxy,
UseProxy = true // Habilitar explícitamente el uso del proxy
};
// Crear un HttpClient con el controlador configurado
using (var httpClient = new HttpClient(handler))
{
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode(); // Lanza una excepción si el código de estado HTTP es un error
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Solicitud exitosa. Fragmento de respuesta:");
Console.WriteLine(responseBody.Substring(0, Math.Min(responseBody.Length, 500))); // Imprimir los primeros 500 caracteres
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error de solicitud: {e.Message}");
}
catch (WebException e)
{
Console.WriteLine($"Error de proxy o de red: {e.Message}");
}
}
}
}
En este ejemplo:
* WebProxy(proxyAddress, BypassOnLocal: false) crea un objeto proxy. BypassOnLocal: false asegura que las solicitudes a direcciones locales (por ejemplo, localhost) también pasen por el proxy, a menos que se omitan explícitamente más tarde.
* handler.UseProxy = true instruye explícitamente al controlador para que use el proxy configurado.
Proxy con autenticación
Si el servidor proxy requiere autenticación (por ejemplo, nombre de usuario y contraseña), establezca la propiedad Credentials del objeto WebProxy utilizando una instancia 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"; // Reemplazar
string proxyUsername = "your_username"; // Reemplazar
string proxyPassword = "your_password"; // Reemplazar
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("Solicitud exitosa con proxy autenticado.");
Console.WriteLine(responseBody.Substring(0, Math.Min(responseBody.Length, 500)));
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error de solicitud: {e.Message}");
}
catch (WebException e)
{
Console.WriteLine($"Error de proxy o de red: {e.Message}");
}
}
}
}
Uso del proxy predeterminado del sistema
HttpClientHandler se puede configurar para usar la configuración de proxy predeterminada del sistema, que generalmente se configura en el sistema operativo o en la configuración de Internet Explorer. Este suele ser el comportamiento deseado en entornos empresariales.
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 // Usar la configuración de proxy predeterminada del sistema
};
using (var httpClient = new HttpClient(handler))
{
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Solicitud exitosa usando el proxy predeterminado del sistema.");
Console.WriteLine(responseBody.Substring(0, Math.Min(responseBody.Length, 500)));
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error de solicitud: {e.Message}");
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
}
}
Establecer UseSystemProxy = true configura automáticamente el HttpClientHandler para descubrir y usar la configuración de proxy definida a nivel del sistema operativo. Si UseSystemProxy es true, la propiedad Proxy se ignora.
Omisión del proxy para direcciones específicas
La clase WebProxy proporciona mecanismos para omitir el proxy para ciertas direcciones.
BypassProxyOnLocal
Establecer BypassProxyOnLocal = true en el constructor o propiedad de WebProxy instruirá al proxy para que no se use para recursos de la intranet local. Esto a menudo es deseable para evitar que el tráfico interno se enrute innecesariamente a través de un proxy externo.
var webProxy = new WebProxy("http://your.proxy.server:8080")
{
BypassProxyOnLocal = true // No usar proxy para direcciones locales
};
BypassList
Para un control más granular, la propiedad BypassList permite especificar una matriz de expresiones regulares que definen las URI para las cuales se debe omitir el proxy.
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"; // URL interna de ejemplo
string externalUrl = "http://external.api.com/data"; // URL externa de ejemplo
// Definir una lista de omisión usando expresiones regulares
string[] bypassList = new string[]
{
"internal\\.api\\.com", // Omisión para internal.api.com
"\\.local$" // Omisión para cualquier host que termine con .local
};
var webProxy = new WebProxy(proxyAddress)
{
BypassList = bypassList,
BypassProxyOnLocal = false // Manejar explícitamente la omisión local a través de BypassList si es necesario
};
var handler = new HttpClientHandler
{
Proxy = webProxy,
UseProxy = true
};
using (var httpClient = new HttpClient(handler))
{
Console.WriteLine($"Intentando solicitud a {targetUrl} (debería omitir el proxy)...");
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode();
Console.WriteLine($"Solicitud a {targetUrl} exitosa. (Verificar registros del proxy si están disponibles)");
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error de solicitud a {targetUrl}: {e.Message}");
}
Console.WriteLine($"\nIntentando solicitud a {externalUrl} (debería usar el proxy)...");
try
{
HttpResponseMessage response = await httpClient.GetAsync(externalUrl);
response.EnsureSuccessStatusCode();
Console.WriteLine($"Solicitud a {externalUrl} exitosa. (Verificar registros del proxy si están disponibles)");
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error de solicitud a {externalUrl}: {e.Message}");
}
}
}
}
HttpClientHandler vs. SocketsHttpHandler
.NET Core 2.1 introdujo SocketsHttpHandler como el controlador predeterminado para HttpClient, ofreciendo un rendimiento mejorado y consistencia multiplataforma. HttpClientHandler aún existe y se puede usar explícitamente, pero SocketsHttpHandler es generalmente preferido para el nuevo desarrollo. Al usar SocketsHttpHandler, la configuración del proxy es ligeramente diferente.
| Característica | HttpClientHandler |
SocketsHttpHandler (Recomendado para .NET Core/.NET 5+) |
|---|---|---|
| Tipo de Proxy | WebProxy |
IWebProxy (a menudo WebProxy o implementación personalizada) |
| Configuración | Establecer la propiedad Proxy con una instancia de WebProxy. |
Establecer la propiedad Proxy con una instancia de IWebProxy. |
| Proxy del Sistema | UseSystemProxy = true |
UseProxy = true y Proxy = WebRequest.DefaultWebProxy o null para el predeterminado del sistema. |
| Autenticación | WebProxy.Credentials |
WebProxy.Credentials (si se usa WebProxy) |
| Proxy SOCKS | No directamente soportado. | Soporte directo para SOCKS5 a través de la propiedad Proxy establecida en new WebProxy("socks5://...") |
| Predeterminado en .NET | Predeterminado para .NET Framework. | Predeterminado para .NET Core 2.1+ / .NET 5+. |
Configuración del proxy con 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 es el predeterminado en .NET moderno, pero se puede usar explícitamente
var handler = new SocketsHttpHandler
{
Proxy = webProxy, // Asignar instancia de IWebProxy
UseProxy = true, // Habilitar explícitamente el uso del proxy
AllowAutoRedirect = true, // Ejemplo de otras propiedades de 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("Solicitud exitosa usando SocketsHttpHandler.");
Console.WriteLine(responseBody.Substring(0, Math.Min(responseBody.Length, 500)));
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error de solicitud: {e.Message}");
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
}
}
Para usar el proxy predeterminado del sistema con SocketsHttpHandler, establezca UseProxy = true y Proxy = WebRequest.DefaultWebProxy. Si Proxy es null y UseProxy es true, SocketsHttpHandler intentará usar el proxy predeterminado del sistema.
Manejo de errores y depuración
Al encontrar problemas con la configuración del proxy, considere lo siguiente:
* Conectividad de red: Verifique que el host de la aplicación pueda alcanzar el servidor proxy.
* Estado del servidor proxy: Asegúrese de que el servidor proxy esté operativo y configurado correctamente.
* Autenticación: Verifique nuevamente las credenciales del proxy. Las credenciales incorrectas a menudo resultan en errores HTTP 407 Proxy Authentication Required.
* Reglas de firewall: Verifique las reglas de firewall locales y de red que puedan bloquear el tráfico hacia o desde el proxy.
* Registros del proxy: Si tiene acceso a los registros del servidor proxy, inspecciónelos en busca de intentos de conexión y errores.
* Excepciones: Capture HttpRequestException y WebException (para HttpClientHandler en .NET Framework) para obtener mensajes de error detallados.
Consideraciones de seguridad
- Confianza: Solo enrute el tráfico a través de servidores proxy de confianza. Los proxies maliciosos pueden interceptar, modificar o registrar datos sensibles.
- Credenciales: Almacene las credenciales del proxy de forma segura, evitando codificarlas directamente en el código fuente. Utilice variables de entorno, archivos de configuración o servicios de gestión de secretos.
- SSL/TLS: Asegúrese de que el proxy maneje correctamente el tráfico SSL/TLS. Si el proxy realiza inspección SSL (Man-in-the-Middle), la aplicación podría requerir confiar en una autoridad de certificación raíz adicional.
HttpClientHandlertiene una propiedadServerCertificateCustomValidationCallbackpara la validación de certificados personalizada, pero esto debe usarse con precaución.