Realización de solicitudes HTTP con la clase HttpClient
En este artículo, aprenderá a realizar solicitudes HTTP y a controlar las respuestas con la clase HttpClient
.
Importante
Todas las solicitudes HTTP de ejemplo de este artículo tienen como destino una de las siguientes direcciones URL:
- https://jsonplaceholder.typicode.com: un sitio que proporciona una plataforma gratuita de API falsa para probar y crear prototipos.
- https://www.example.com: un dominio disponible para su uso en ejemplos ilustrativos en documentos.
Normalmente, los puntos de conexión HTTP devuelven datos de notación de objetos JavaScript (JSON), pero no siempre. Para mayor comodidad, el paquete NuGet opcional System.Net.Http.Json proporciona varios métodos de extensión para HttpClient
y HttpContent
objetos que realizan la serialización y deserialización automáticas mediante el paquete NuGet 📦 System.Text.Json. Los ejemplos de este artículo llaman la atención a los lugares en los que estas extensiones están disponibles.
Sugerencia
Todo el código fuente al que se hace referencia en este artículo está disponible en el repositorio GitHub: .NET Docs.
Creación de un objeto HttpClient
La mayoría de los ejemplos de este artículo reutilizan la misma instancia de HttpClient
, por lo que puede configurar la instancia una vez y usarla para los ejemplos restantes. Para crear un objeto HttpClient
, use el constructor de clase HttpClient
. Para obtener más información, consulte Directrices para usar HttpClient.
// HttpClient lifecycle management best practices:
// https://learn.microsoft.com/dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use
private static HttpClient sharedClient = new()
{
BaseAddress = new Uri("https://jsonplaceholder.typicode.com"),
};
El código completa las siguientes tareas:
- Cree una nueva instancia de
HttpClient
como variablestatic
. Según las directrices de , el enfoque recomendado consiste en reutilizar las instancias deHttpClient
durante el ciclo de vida de la aplicación. - Establezca la propiedad HttpClient.BaseAddress en
"https://jsonplaceholder.typicode.com"
.
Esta instancia de HttpClient
usa la dirección base para realizar solicitudes posteriores. Para aplicar otras configuraciones, tenga en cuenta las SIGUIENTES API:
- Establecer la propiedad HttpClient.DefaultRequestHeaders.
- Aplique una propiedad HttpClient.Timeout no predeterminada.
- Especifique la propiedad HttpClient.DefaultRequestVersion.
Sugerencia
Como alternativa, puede crear instancias HttpClient
mediante un enfoque de patrón de fábrica que le permita configurar cualquier número de clientes y consumirlos como servicios de inserción de dependencias. Para obtener más información, consulte fábrica de cliente HTTP con .NET.
Realización de una solicitud HTTP
Para realizar una solicitud HTTP, llame a cualquiera de los métodos de API siguientes:
HTTP method | API |
---|---|
GET |
HttpClient.GetAsync |
GET |
HttpClient.GetByteArrayAsync |
GET |
HttpClient.GetStreamAsync |
GET |
HttpClient.GetStringAsync |
POST |
HttpClient.PostAsync |
PUT |
HttpClient.PutAsync |
PATCH |
HttpClient.PatchAsync |
DELETE |
HttpClient.DeleteAsync |
†USER SPECIFIED |
HttpClient.SendAsync |
†Una solicitud
USER SPECIFIED
indica que el métodoSendAsync
acepta cualquier objeto HttpMethod válido.
Advertencia
La realización de solicitudes HTTP se consideran tareas enlazadas a E/S de red. Existe un método de HttpClient.Send sincrónico, pero la recomendación es usar las API asincrónicas en su lugar, a menos que tenga una buena razón para no hacerlo.
Nota:
Aunque el destino es dispositivos Android (por ejemplo, con el desarrollo de MAUI de .NET), debe agregar la definición de android:usesCleartextTraffic="true"
a la sección <application></application>
del archivo AndroidManifest.xml. Esta configuración habilita el tráfico de texto no cifrado, como las solicitudes HTTP, que se deshabilitan de forma predeterminada debido a las directivas de seguridad de Android. Considere la siguiente configuración XML de ejemplo:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:usesCleartextTraffic="true"></application>
<!-- omitted for brevity -->
</manifest>
Para obtener más información, consulte Habilitar tráfico de red de texto no cifrado para el dominio localhost.
Descripción del contenido HTTP
El tipo HttpContent se usa para representar un cuerpo de entidad HTTP y los encabezados de contenido correspondientes. Para los métodos HTTP (o métodos de solicitud) que requieren un cuerpo (POST
, PUT
, PATCH
), use la clase HttpContent para especificar el cuerpo de la solicitud. La mayoría de los ejemplos muestran cómo preparar la subclase StringContent con una carga JSON, pero existen otras subclases para diferentes tipos de contenido (MIME).
- ByteArrayContent: proporciona contenido HTTP basado en una matriz de bytes.
- FormUrlEncodedContent: proporciona contenido HTTP para tuplas de nombre y valor codificadas mediante el tipo MIME de
"application/x-www-form-urlencoded"
. - JsonContent: proporciona contenido HTTP basado en JSON.
- MultipartContent: proporciona una colección de objetos HttpContent que se serializan mediante la especificación de tipo MIME de
"multipart/*"
. - MultipartFormDataContent: proporciona un contenedor para el contenido codificado mediante el tipo MIME de
"multipart/form-data"
. - ReadOnlyMemoryContent: proporciona contenido HTTP basado en un valor de ReadOnlyMemory<T>.
- StreamContent: proporciona contenido HTTP basado en una secuencia.
- StringContent: proporciona contenido HTTP basado en una cadena.
La clase HttpContent
también se usa para representar el cuerpo de respuesta de la clase HttpResponseMessage, que es accesible en la propiedad HttpResponseMessage.Content.
Uso de una solicitud HTTP GET
Una solicitud GET
no debe enviar un cuerpo. Esta solicitud se usa (como indica el nombre del método) para recuperar (o obtener) datos de un recurso. Para realizar una solicitud de GET
HTTP dada una instancia de HttpClient
y un objeto Uri, use el método HttpClient.GetAsync:
static async Task GetAsync(HttpClient httpClient)
{
using HttpResponseMessage response = await httpClient.GetAsync("todos/3");
response.EnsureSuccessStatusCode()
.WriteRequestToConsole();
var jsonResponse = await response.Content.ReadAsStringAsync();
Console.WriteLine($"{jsonResponse}\n");
// Expected output:
// GET https://jsonplaceholder.typicode.com/todos/3 HTTP/1.1
// {
// "userId": 1,
// "id": 3,
// "title": "fugiat veniam minus",
// "completed": false
// }
}
El código completa las siguientes tareas:
- Realice una solicitud
GET
al endpoint"https://jsonplaceholder.typicode.com/todos/3"
. - Asegúrese de que la respuesta sea exitosa.
- Escriba los detalles de la solicitud en la consola.
- Lea el cuerpo de la respuesta como una cadena.
- Escriba el cuerpo de la respuesta JSON en la consola.
El método WriteRequestToConsole
es una extensión personalizada que no forma parte del marco de trabajo. Si tiene curiosidad sobre la implementación, tenga en cuenta el siguiente código de C#:
static class HttpResponseMessageExtensions
{
internal static void WriteRequestToConsole(this HttpResponseMessage response)
{
if (response is null)
{
return;
}
var request = response.RequestMessage;
Console.Write($"{request?.Method} ");
Console.Write($"{request?.RequestUri} ");
Console.WriteLine($"HTTP/{request?.Version}");
}
}
Esta funcionalidad se usa para escribir los detalles de la solicitud en la consola de la siguiente forma:
<HTTP Request Method> <Request URI> <HTTP/Version>
Por ejemplo, la solicitud de GET
al punto de conexión de "https://jsonplaceholder.typicode.com/todos/3"
genera el siguiente mensaje:
GET https://jsonplaceholder.typicode.com/todos/3 HTTP/1.1
Creación de la solicitud HTTP GET a partir de JSON
El punto de conexión de https://jsonplaceholder.typicode.com/todos devuelve una matriz JSON de objetos Todo
. Su estructura JSON es similar a la siguiente forma:
[
{
"userId": 1,
"id": 1,
"title": "example title",
"completed": false
},
{
"userId": 1,
"id": 2,
"title": "another example title",
"completed": true
},
]
El objeto Todo
de C# se define del modo siguiente:
public record class Todo(
int? UserId = null,
int? Id = null,
string? Title = null,
bool? Completed = null);
Es un tipo record class
, con las propiedades opcionales Id
, Title
, Completed
y UserId
. Para obtener más información sobre el tipo record
, vea Introducción a los tipos de registro en C#. Para deserializar automáticamente las solicitudes GET
en un objeto C# fuertemente tipado, use el método de extensión GetFromJsonAsync que forma parte del paquete NuGet 📦System.Net.Http.Json.
static async Task GetFromJsonAsync(HttpClient httpClient)
{
var todos = await httpClient.GetFromJsonAsync<List<Todo>>(
"todos?userId=1&completed=false");
Console.WriteLine("GET https://jsonplaceholder.typicode.com/todos?userId=1&completed=false HTTP/1.1");
todos?.ForEach(Console.WriteLine);
Console.WriteLine();
// Expected output:
// GET https://jsonplaceholder.typicode.com/todos?userId=1&completed=false HTTP/1.1
// Todo { UserId = 1, Id = 1, Title = delectus aut autem, Completed = False }
// Todo { UserId = 1, Id = 2, Title = quis ut nam facilis et officia qui, Completed = False }
// Todo { UserId = 1, Id = 3, Title = fugiat veniam minus, Completed = False }
// Todo { UserId = 1, Id = 5, Title = laboriosam mollitia et enim quasi adipisci quia provident illum, Completed = False }
// Todo { UserId = 1, Id = 6, Title = qui ullam ratione quibusdam voluptatem quia omnis, Completed = False }
// Todo { UserId = 1, Id = 7, Title = illo expedita consequatur quia in, Completed = False }
// Todo { UserId = 1, Id = 9, Title = molestiae perspiciatis ipsa, Completed = False }
// Todo { UserId = 1, Id = 13, Title = et doloremque nulla, Completed = False }
// Todo { UserId = 1, Id = 18, Title = dolorum est consequatur ea mollitia in culpa, Completed = False }
}
El código completa las siguientes tareas:
Realice una solicitud
GET
a"https://jsonplaceholder.typicode.com/todos?userId=1&completed=false"
.La cadena de consulta representa los criterios de filtrado de la solicitud. Cuando el comando se realiza correctamente, la respuesta se deserializa automáticamente en un objeto
List<Todo>
.Escriba los detalles de la solicitud en la consola, junto con cada objeto
Todo
.
Uso de una solicitud HTTP POST
Una solicitud POST
envía datos al servidor para su procesamiento. El encabezado Content-Type
de la solicitud indica qué tipo MIME envía el cuerpo. Para realizar una solicitud de POST
HTTP dada una instancia de HttpClient
y un objeto Uri, use el método HttpClient.PostAsync:
static async Task PostAsync(HttpClient httpClient)
{
using StringContent jsonContent = new(
JsonSerializer.Serialize(new
{
userId = 77,
id = 1,
title = "write code sample",
completed = false
}),
Encoding.UTF8,
"application/json");
using HttpResponseMessage response = await httpClient.PostAsync(
"todos",
jsonContent);
response.EnsureSuccessStatusCode()
.WriteRequestToConsole();
var jsonResponse = await response.Content.ReadAsStringAsync();
Console.WriteLine($"{jsonResponse}\n");
// Expected output:
// POST https://jsonplaceholder.typicode.com/todos HTTP/1.1
// {
// "userId": 77,
// "id": 201,
// "title": "write code sample",
// "completed": false
// }
}
El código completa las siguientes tareas:
- Prepare una instancia StringContent con el cuerpo JSON de la solicitud (tipo MIME de
"application/json"
). - Realice una solicitud
POST
al endpoint"https://jsonplaceholder.typicode.com/todos"
. - Asegúrese de que la respuesta es correcta y escriba los detalles de la solicitud en la consola.
- Escriba el cuerpo de la respuesta como una cadena en la consola.
Creación de la solicitud HTTP POST como JSON
Para serializar automáticamente los argumentos de solicitud POST
y deserializar las respuestas en objetos C# fuertemente tipados, use el método de extensión PostAsJsonAsync que forma parte del paquete NuGet System.Net.Http.Json.
static async Task PostAsJsonAsync(HttpClient httpClient)
{
using HttpResponseMessage response = await httpClient.PostAsJsonAsync(
"todos",
new Todo(UserId: 9, Id: 99, Title: "Show extensions", Completed: false));
response.EnsureSuccessStatusCode()
.WriteRequestToConsole();
var todo = await response.Content.ReadFromJsonAsync<Todo>();
Console.WriteLine($"{todo}\n");
// Expected output:
// POST https://jsonplaceholder.typicode.com/todos HTTP/1.1
// Todo { UserId = 9, Id = 201, Title = Show extensions, Completed = False }
}
El código completa las siguientes tareas:
- Serialice la instancia
Todo
como JSON y realice una solicitudPOST
al endpoint de"https://jsonplaceholder.typicode.com/todos"
. - Asegúrese de que la respuesta es correcta y escriba los detalles de la solicitud en la consola.
- Deserialice el cuerpo de la respuesta en una instancia
Todo
y escriba el objetoTodo
en la consola.
Uso de una solicitud HTTP PUT
El método de solicitud PUT
reemplaza un recurso existente o crea uno nuevo utilizando la carga útil del cuerpo de la solicitud. Para realizar una solicitud de PUT
HTTP dada una instancia de HttpClient
y un objeto Uri, use el método HttpClient.PutAsync:
static async Task PutAsync(HttpClient httpClient)
{
using StringContent jsonContent = new(
JsonSerializer.Serialize(new
{
userId = 1,
id = 1,
title = "foo bar",
completed = false
}),
Encoding.UTF8,
"application/json");
using HttpResponseMessage response = await httpClient.PutAsync(
"todos/1",
jsonContent);
response.EnsureSuccessStatusCode()
.WriteRequestToConsole();
var jsonResponse = await response.Content.ReadAsStringAsync();
Console.WriteLine($"{jsonResponse}\n");
// Expected output:
// PUT https://jsonplaceholder.typicode.com/todos/1 HTTP/1.1
// {
// "userId": 1,
// "id": 1,
// "title": "foo bar",
// "completed": false
// }
}
El código completa las siguientes tareas:
- Prepare una instancia StringContent con el cuerpo JSON de la solicitud (tipo MIME de
"application/json"
). - Realice una solicitud
PUT
al endpoint"https://jsonplaceholder.typicode.com/todos/1"
. - Asegúrate de que la respuesta sea exitosa y escribe en la consola los detalles de la solicitud junto con el cuerpo de la respuesta JSON.
Creación de la solicitud HTTP PUT como JSON
Para serializar automáticamente los argumentos de solicitud PUT
y deserializar las respuestas en objetos C# fuertemente tipados, use el método de extensión PutAsJsonAsync que forma parte del paquete NuGet System.Net.Http.Json.
static async Task PutAsJsonAsync(HttpClient httpClient)
{
using HttpResponseMessage response = await httpClient.PutAsJsonAsync(
"todos/5",
new Todo(Title: "partially update todo", Completed: true));
response.EnsureSuccessStatusCode()
.WriteRequestToConsole();
var todo = await response.Content.ReadFromJsonAsync<Todo>();
Console.WriteLine($"{todo}\n");
// Expected output:
// PUT https://jsonplaceholder.typicode.com/todos/5 HTTP/1.1
// Todo { UserId = , Id = 5, Title = partially update todo, Completed = True }
}
El código completa las siguientes tareas:
- Serialice la instancia de
Todo
en formato JSON y realice una solicitudPUT
al endpoint"https://jsonplaceholder.typicode.com/todos/5"
. - Asegúrese de que la respuesta es correcta y escriba los detalles de la solicitud en la consola.
- Deserialice el cuerpo de la respuesta en una instancia
Todo
y escriba los objetosTodo
en la consola.
Utilice una solicitud HTTP PATCH
La solicitud PATCH
es una actualización parcial de un recurso existente. Esta solicitud no crea un nuevo recurso y no está pensado para reemplazar un recurso existente. En su lugar, este método solo actualiza parcialmente un recurso. Para realizar una solicitud de PATCH
HTTP dada una instancia de HttpClient
y un objeto Uri, use el método HttpClient.PatchAsync:
static async Task PatchAsync(HttpClient httpClient)
{
using StringContent jsonContent = new(
JsonSerializer.Serialize(new
{
completed = true
}),
Encoding.UTF8,
"application/json");
using HttpResponseMessage response = await httpClient.PatchAsync(
"todos/1",
jsonContent);
response.EnsureSuccessStatusCode()
.WriteRequestToConsole();
var jsonResponse = await response.Content.ReadAsStringAsync();
Console.WriteLine($"{jsonResponse}\n");
// Expected output
// PATCH https://jsonplaceholder.typicode.com/todos/1 HTTP/1.1
// {
// "userId": 1,
// "id": 1,
// "title": "delectus aut autem",
// "completed": true
// }
}
El código completa las siguientes tareas:
- Prepare una instancia StringContent con el cuerpo JSON de la solicitud (tipo MIME de
"application/json"
). - Haga una solicitud
PATCH
al punto de conexión"https://jsonplaceholder.typicode.com/todos/1"
. - Asegúrese de que la respuesta sea exitosa y escriba los detalles de la solicitud junto con el cuerpo de la respuesta JSON en la consola.
No existen métodos de extensión para las solicitudes PATCH
en el paquete NuGet System.Net.Http.Json
.
Uso de una solicitud HTTP DELETE
Una solicitud de DELETE
quita un recurso existente y la solicitud es idempotente, pero no segura. Varias solicitudes de DELETE
a los mismos recursos producen el mismo resultado, pero la solicitud afecta al estado del recurso. Para realizar una solicitud de DELETE
HTTP dada una instancia de HttpClient
y un objeto Uri, use el método HttpClient.DeleteAsync:
static async Task DeleteAsync(HttpClient httpClient)
{
using HttpResponseMessage response = await httpClient.DeleteAsync("todos/1");
response.EnsureSuccessStatusCode()
.WriteRequestToConsole();
var jsonResponse = await response.Content.ReadAsStringAsync();
Console.WriteLine($"{jsonResponse}\n");
// Expected output
// DELETE https://jsonplaceholder.typicode.com/todos/1 HTTP/1.1
// {}
}
El código completa las siguientes tareas:
- Haga una solicitud
DELETE
al endpoint"https://jsonplaceholder.typicode.com/todos/1"
. - Asegúrese de que la respuesta es correcta y escriba los detalles de la solicitud en la consola.
Sugerencia
La respuesta a una solicitud DELETE
(al igual que una solicitud PUT
) puede incluir o no un cuerpo.
Exploración de la solicitud HTTP HEAD
La solicitud HEAD
es similar a una solicitud GET
. En lugar de devolver el recurso, esta solicitud devuelve solo los encabezados asociados al recurso. Una respuesta a la solicitud HEAD
no devuelve un cuerpo. Para realizar una solicitud de HEAD
HTTP dada una instancia de HttpClient
y un objeto Uri, use el método HttpClient.SendAsync con el tipo HttpMethod establecido en HttpMethod.Head
:
static async Task HeadAsync(HttpClient httpClient)
{
using HttpRequestMessage request = new(
HttpMethod.Head,
"https://www.example.com");
using HttpResponseMessage response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode()
.WriteRequestToConsole();
foreach (var header in response.Headers)
{
Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
}
Console.WriteLine();
// Expected output:
// HEAD https://www.example.com/ HTTP/1.1
// Accept-Ranges: bytes
// Age: 550374
// Cache-Control: max-age=604800
// Date: Wed, 10 Aug 2022 17:24:55 GMT
// ETag: "3147526947"
// Server: ECS, (cha / 80E2)
// X-Cache: HIT
}
El código completa las siguientes tareas:
- Haga una solicitud
HEAD
al punto de conexión"https://www.example.com/"
. - Asegúrese de que la respuesta es correcta y escriba los detalles de la solicitud en la consola.
- Recorra en iteración todos los encabezados de respuesta y escriba cada encabezado en la consola.
Exploración de la solicitud HTTP OPTIONS
La solicitud OPTIONS
se usa para identificar qué métodos HTTP admite un servidor o punto de conexión. Para realizar una solicitud de OPTIONS
HTTP dada una instancia de HttpClient
y un objeto Uri, use el método HttpClient.SendAsync con el tipo HttpMethod establecido en HttpMethod.Options
:
static async Task OptionsAsync(HttpClient httpClient)
{
using HttpRequestMessage request = new(
HttpMethod.Options,
"https://www.example.com");
using HttpResponseMessage response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode()
.WriteRequestToConsole();
foreach (var header in response.Content.Headers)
{
Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
}
Console.WriteLine();
// Expected output
// OPTIONS https://www.example.com/ HTTP/1.1
// Allow: OPTIONS, GET, HEAD, POST
// Content-Type: text/html; charset=utf-8
// Expires: Wed, 17 Aug 2022 17:28:42 GMT
// Content-Length: 0
}
El código completa las siguientes tareas:
- Envíe una solicitud HTTP
OPTIONS
al punto de conexión de"https://www.example.com/"
. - Asegúrese de que la respuesta es correcta y escriba los detalles de la solicitud en la consola.
- Recorra en iteración todos los encabezados de contenido de la respuesta y escriba cada encabezado en la consola.
Exploración de la solicitud HTTP TRACE
La solicitud TRACE
puede ser útil para la depuración, ya que proporciona un bucle invertido en el nivel de aplicación del mensaje de solicitud. Para realizar una solicitud HTTP de TRACE
, cree un HttpRequestMessage usando el tipo HttpMethod.Trace
.
using HttpRequestMessage request = new(
HttpMethod.Trace,
"{ValidRequestUri}");
Precaución
No todos los servidores HTTP admiten el método HTTP de TRACE
. Este método puede exponer una vulnerabilidad de seguridad si se usa de forma imprudente. Para obtener más información, vea Open Web Application Security Project (OWASP): Cross Site Tracing.
Control de una respuesta HTTP
Al manejar una respuesta HTTP, interactúe con el tipo HttpResponseMessage. Varios miembros se usan para evaluar la validez de una respuesta. El código de estado HTTP está disponible en la propiedad HttpResponseMessage.StatusCode.
Supongamos que envía una solicitud dada una instancia de cliente:
using HttpResponseMessage response = await httpClient.SendAsync(request);
Para asegurarse de que el response
es OK
(código de estado HTTP 200), puede evaluar el valor como se muestra en el ejemplo siguiente:
if (response is { StatusCode: HttpStatusCode.OK })
{
// Omitted for brevity...
}
Hay otros códigos de estado HTTP que representan una respuesta correcta, como CREATED
(código de estado HTTP 201), ACCEPTED
(código de estado HTTP 202), NO CONTENT
(código de estado HTTP 204) y RESET CONTENT
(código de estado HTTP 205). También puede usar la propiedad HttpResponseMessage.IsSuccessStatusCode para evaluar estos códigos, lo que garantiza que el código de estado de respuesta esté dentro del intervalo 200-299:
if (response.IsSuccessStatusCode)
{
// Omitted for brevity...
}
Si necesita que el marco produzca el error HttpRequestException, puede llamar al método HttpResponseMessage.EnsureSuccessStatusCode():
response.EnsureSuccessStatusCode();
Este código produce un error de HttpRequestException
si el código de estado de respuesta no está dentro del intervalo 200-299.
Explora las respuestas de contenido válidas HTTP
Con una respuesta correcta, puede acceder al cuerpo de la respuesta usando la propiedad Content. El cuerpo está disponible como una instancia de HttpContent, que puede usar para acceder al cuerpo como una secuencia, una matriz de bytes o una cadena.
El código siguiente usa el objeto responseStream
para leer el cuerpo de la respuesta:
await using Stream responseStream =
await response.Content.ReadAsStreamAsync();
Puede usar objetos diferentes para leer el cuerpo de la respuesta. Use el objeto responseByteArray
para leer el cuerpo de la respuesta:
byte[] responseByteArray = await response.Content.ReadAsByteArrayAsync();
Use el objeto responseString
para leer el cuerpo de la respuesta:
string responseString = await response.Content.ReadAsStringAsync();
Cuando sepa que un punto de conexión HTTP devuelve JSON, puede deserializar el cuerpo de la respuesta en cualquier objeto de C# válido mediante el paquete NuGet System.Net.Http.Json:
T? result = await response.Content.ReadFromJsonAsync<T>();
En este código, el valor de result
es el cuerpo de la respuesta deserializado como el tipo T
.
Uso del control de errores HTTP
Cuando se produce un error en una solicitud HTTP, el sistema inicia el objeto HttpRequestException. Es posible que la detección de la excepción por sí sola no sea suficiente. Hay otras posibles excepciones que es posible que quiera considerar manejar. Por ejemplo, el código de llamada podría usar un token de cancelación que se canceló antes de que se complete la solicitud. En este escenario, puede detectar el error TaskCanceledException:
using var cts = new CancellationTokenSource();
try
{
// Assuming:
// httpClient.Timeout = TimeSpan.FromSeconds(10)
using var response = await httpClient.GetAsync(
"http://localhost:5001/sleepFor?seconds=100", cts.Token);
}
catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
{
// When the token has been canceled, it is not a timeout.
Console.WriteLine($"Canceled: {ex.Message}");
}
Del mismo modo, cuando se realiza una solicitud HTTP, si el servidor no responde antes de que se supere el valor de HttpClient.Timeout, se produce la misma excepción. En este escenario, puede distinguir si ha habido tiempo de espera mediante la evaluación de la propiedad Exception.InnerException al detectar el error TaskCanceledException:
try
{
// Assuming:
// httpClient.Timeout = TimeSpan.FromSeconds(10)
using var response = await httpClient.GetAsync(
"http://localhost:5001/sleepFor?seconds=100");
}
catch (OperationCanceledException ex) when (ex.InnerException is TimeoutException tex)
{
Console.WriteLine($"Timed out: {ex.Message}, {tex.Message}");
}
En el código, cuando la excepción interna es un tipo de TimeoutException, se agota el tiempo de espera y el token de cancelación no cancela la solicitud.
Para evaluar el código de estado HTTP al detectar el objeto HttpRequestException, puede evaluar la propiedad HttpRequestException.StatusCode:
try
{
// Assuming:
// httpClient.Timeout = TimeSpan.FromSeconds(10)
using var response = await httpClient.GetAsync(
"http://localhost:5001/doesNotExist");
response.EnsureSuccessStatusCode();
}
catch (HttpRequestException ex) when (ex is { StatusCode: HttpStatusCode.NotFound })
{
// Handle 404
Console.WriteLine($"Not found: {ex.Message}");
}
En el código, se llama al método EnsureSuccessStatusCode() para producir una excepción si la respuesta no se realiza correctamente. A continuación, la propiedad HttpRequestException.StatusCode se evalúa para determinar si la respuesta era 404
(código de estado HTTP 404). Hay varios métodos auxiliares en el objeto HttpClient
que llaman implícitamente al método EnsureSuccessStatusCode
en su nombre.
Para la gestión de errores HTTP, tenga en cuenta las siguientes API:
- método HttpClient.GetByteArrayAsync
- método HttpClient.GetStreamAsync
- método HttpClient.GetStringAsync
Sugerencia
Todos los métodos HttpClient
usados para realizar solicitudes HTTP que no devuelven un tipo de HttpResponseMessage
llaman implícitamente al método EnsureSuccessStatusCode
en su nombre.
Al llamar a estos métodos, puede controlar el objeto HttpRequestException
y evaluar la propiedad HttpRequestException.StatusCode para determinar el código de estado HTTP de la respuesta:
try
{
// These extension methods will throw HttpRequestException
// with StatusCode set when the HTTP request status code isn't 2xx:
//
// GetByteArrayAsync
// GetStreamAsync
// GetStringAsync
using var stream = await httpClient.GetStreamAsync(
"https://localhost:5001/doesNotExists");
}
catch (HttpRequestException ex) when (ex is { StatusCode: HttpStatusCode.NotFound })
{
// Handle 404
Console.WriteLine($"Not found: {ex.Message}");
}
Puede haber escenarios en los que necesite lanzar el objeto HttpRequestException en su código. El constructor HttpRequestException() es público y puede usarlo para producir una excepción con un mensaje personalizado:
try
{
using var response = await httpClient.GetAsync(
"https://localhost:5001/doesNotExists");
// Throw for anything higher than 400.
if (response is { StatusCode: >= HttpStatusCode.BadRequest })
{
throw new HttpRequestException(
"Something went wrong", inner: null, response.StatusCode);
}
}
catch (HttpRequestException ex) when (ex is { StatusCode: HttpStatusCode.NotFound })
{
Console.WriteLine($"Not found: {ex.Message}");
}
Configuración de un proxy HTTP
Un proxy HTTP se puede configurar de dos maneras. Se especifica un valor predeterminado en la propiedad HttpClient.DefaultProxy. Como alternativa, puede especificar un proxy en la propiedad HttpClientHandler.Proxy.
Uso de un proxy predeterminado global
La propiedad HttpClient.DefaultProxy
es una propiedad estática que determina el proxy predeterminado que usan todas las instancias de HttpClient
, si no se establece ningún proxy explícitamente en el objeto HttpClientHandler pasado a través de su constructor.
La instancia predeterminada devuelta por esta propiedad inicializa según un conjunto diferente de reglas en función de la plataforma:
- Windows: lea la configuración de proxy de las variables de entorno o, si no se definen, de la configuración del proxy del usuario.
- macOS: lea la configuración de proxy de las variables de entorno o, si no se definen, de la configuración del proxy del sistema.
- Linux: Leer la configuración del proxy de las variables de entorno, o si no están definidas, iniciar una instancia no configurada para pasar por alto todas las direcciones.
La inicialización de la propiedad DefaultProxy
en plataformas basadas en Windows y Unix usa las siguientes variables de entorno:
HTTP_PROXY
: servidor proxy usado en solicitudes HTTP.HTTPS_PROXY
: el servidor proxy que se usa en las solicitudes HTTPS.ALL_PROXY
: el servidor proxy que se usa en solicitudes HTTP o HTTPS cuando no se definen las variablesHTTP_PROXY
oHTTPS_PROXY
.NO_PROXY
: Una lista separada por comas de nombres de host que se excluirán del uso del proxy. Los asteriscos no se admiten como caracteres comodín. Use un punto inicial (.) cuando desee que coincida con un subdominio. Ejemplos:NO_PROXY=.example.com
(con el punto inicial) coincide conwww.example.com
, pero no coincide conexample.com
.NO_PROXY=example.com
(sin período inicial) no coincide conwww.example.com
. Este comportamiento se podría revisar en el futuro para que coincida mejor con otros ecosistemas.
En sistemas en los que las variables de entorno distinguen entre mayúsculas y minúsculas, los nombres de las variables pueden estar todas en minúsculas o en mayúsculas. Los nombres en minúsculas se comprueban primero.
El servidor proxy puede ser un nombre de host o una dirección IP, seguido opcionalmente de dos puntos y un número de puerto, o puede ser una URL http
, que opcionalmente incluya un nombre de usuario y una contraseña para la autenticación del proxy. La dirección URL debe comenzar con http
, no https
y no puede incluir ningún texto después del nombre de host, ip o puerto.
Configuración del proxy por cliente
La propiedad HttpClientHandler.Proxy identifica el objeto WebProxy que se va a usar para procesar solicitudes a recursos de Internet. Para especificar que no se debe usar ningún proxy, establezca la propiedad Proxy
en la instancia de proxy devuelta por el método GlobalProxySelection.GetEmptyWebProxy().
El archivo de configuración del equipo local o la aplicación puede especificar que se usa un proxy predeterminado. Si se especifica la propiedad Proxy
, la configuración de proxy de la propiedad Proxy
invalida el archivo de configuración del equipo local o la aplicación y el controlador usa la configuración de proxy especificada. Si no se especifica ningún proxy en un archivo de configuración y no se especifica la propiedad Proxy
, el controlador usa la configuración de proxy heredada del equipo local. Si no hay ninguna configuración de proxy, la solicitud se envía directamente al servidor.
La clase HttpClientHandler analiza una lista de omisión de proxy con caracteres comodín heredados de la configuración del equipo local. Por ejemplo, la clase HttpClientHandler
analiza una lista de omisión de "nt*"
de exploradores como una expresión regular de "nt.*"
. Por lo tanto, una dirección URL de http://nt.com
omite el proxy mediante la clase HttpClientHandler
.
La clase HttpClientHandler
admite la omisión del proxy local. La clase considera que un destino es local si se cumple alguna de las condiciones siguientes:
- El destino contiene un nombre plano (sin puntos (.) en la dirección URL).
- El destino contiene una dirección de loopback (Loopback o IPv6Loopback) o el destino contiene una propiedad IPAddress asignada al equipo local.
- El sufijo de dominio del destino coincide con el sufijo de dominio del equipo local, tal como se define en la propiedad DomainName.
Para obtener más información sobre cómo configurar un proxy, consulte las SIGUIENTES API:
- Propiedad WebProxy.Address
- Propiedad WebProxy.BypassProxyOnLocal
- Propiedad WebProxy.BypassArrayList