Compartir a través de


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:

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 variable static. Según las directrices de , el enfoque recomendado consiste en reutilizar las instancias de HttpClient 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:

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étodo SendAsync 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 solicitud POST 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 objeto Todo 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 solicitud PUT 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 objetos Todo 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:

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 variables HTTP_PROXY o HTTPS_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 con www.example.com, pero no coincide con example.com. NO_PROXY=example.com (sin período inicial) no coincide con www.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 httpsy 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:

Pasos siguientes