Fazer solicitações HTTP com a classe HttpClient

Neste artigo, você aprenderá como fazer solicitações HTTP e lidar com respostas com a HttpClient classe.

Importante

Todas as solicitações HTTP de exemplo visam uma das seguintes URLs:

Os pontos de extremidade HTTP geralmente retornam dados JSON (JavaScript Object Notation), mas nem sempre. Por conveniência, o pacote opcional System.Net.Http.Json NuGet fornece vários métodos de extensão para HttpClient e HttpContent que executam serialização e desserialização automática usando System.Text.Json. Os exemplos que se seguem chamam a atenção para locais onde estas extensões estão disponíveis.

Gorjeta

Todo o código-fonte deste artigo está disponível no repositório GitHub: .NET Docs .

Criar um HttpClient

A maioria dos exemplos a seguir reutiliza a mesma HttpClient instância e, portanto, só precisa ser configurada uma vez. Para criar um HttpClient, use o construtor de HttpClient classe. Para obter mais informações, consulte Diretrizes 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"),
};

O código anterior:

  • Instancia uma nova HttpClient instância como uma static variável. De acordo com as diretrizes, recomenda-se reutilizar HttpClient instâncias durante o ciclo de vida do aplicativo.
  • Define o HttpClient.BaseAddress como "https://jsonplaceholder.typicode.com".

Esta HttpClient instância usa o endereço base ao fazer solicitações subsequentes. Para aplicar outra configuração, considere:

Gorjeta

Como alternativa, você pode criar HttpClient instâncias usando uma abordagem de padrão de fábrica que permite configurar qualquer número de clientes e consumi-los como serviços de injeção de dependência. Para obter mais informações, consulte Fábrica de cliente HTTP com .NET.

Fazer uma solicitação HTTP

Para fazer uma solicitação HTTP, chame qualquer uma das seguintes APIs:

Método HTTP 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

Uma USER SPECIFIED solicitação indica que o SendAsync método aceita qualquer arquivo .HttpMethod

Aviso

Fazer solicitações HTTP é considerado trabalho vinculado a E/S de rede. Embora haja um método síncrono HttpClient.Send , é recomendável usar as APIs assíncronas, a menos que você tenha um bom motivo para não fazê-lo.

Conteúdo HTTP

O HttpContent tipo é usado para representar um corpo de entidade HTTP e cabeçalhos de conteúdo correspondentes. Para métodos HTTP (ou métodos de solicitação) que exigem um corpo, POST, PUTe PATCH, use a HttpContent classe para especificar o corpo da solicitação. A maioria dos exemplos mostra como preparar a StringContent subclasse com uma carga JSON útil, mas existem outras subclasses para diferentes tipos de conteúdo (MIME).

A HttpContent classe também é usada para representar o corpo de resposta do HttpResponseMessage, acessível na HttpResponseMessage.Content propriedade.

HTTP Get

Uma GET solicitação não deve enviar um corpo e é usada (como o nome do método indica) para recuperar (ou obter) dados de um recurso. Para fazer uma solicitação HTTP GET , dado um HttpClient e um URI, use o HttpClient.GetAsync método:

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
    //   }
}

O código anterior:

  • Faz uma GET solicitação para "https://jsonplaceholder.typicode.com/todos/3".
  • Garante que a resposta seja bem-sucedida.
  • Grava os detalhes da solicitação no console.
  • Lê o corpo da resposta como uma cadeia de caracteres.
  • Grava o corpo da resposta JSON no console.

O WriteRequestToConsole é um método de extensão personalizado que não faz parte da estrutura, mas se você estiver curioso sobre como ele é implementado, considere o seguinte código 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}");        
    }
}

Essa funcionalidade é usada para gravar os detalhes da solicitação no console da seguinte forma:

<HTTP Request Method> <Request URI> <HTTP/Version>

Como exemplo, a GET solicitação para https://jsonplaceholder.typicode.com/todos/3 gera a seguinte mensagem:

GET https://jsonplaceholder.typicode.com/todos/3 HTTP/1.1

HTTP Obter de JSON

O https://jsonplaceholder.typicode.com/todos ponto de extremidade retorna uma matriz JSON de objetos "todo". Sua estrutura JSON é semelhante à seguinte:

[
  {
    "userId": 1,
    "id": 1,
    "title": "example title",
    "completed": false
  },
  {
    "userId": 1,
    "id": 2,
    "title": "another example title",
    "completed": true
  },
]

O objeto C# Todo é definido da seguinte forma:

public record class Todo(
    int? UserId = null,
    int? Id = null,
    string? Title = null,
    bool? Completed = null);

É um record class tipo, com opcional Id, Title, Completed, e UserId propriedades. Para obter mais informações sobre o record tipo, consulte Introdução aos tipos de registro em C#. Para desserializar GET automaticamente solicitações em objeto C# fortemente tipado, use o GetFromJsonAsync método de extensão que faz parte do pacote 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 }
}

No código anterior:

  • É feito um GET pedido para "https://jsonplaceholder.typicode.com/todos?userId=1&completed=false".
    • A cadeia de caracteres de consulta representa os critérios de filtragem para a solicitação.
  • A resposta é automaticamente desserializada em um List<Todo> quando bem-sucedida.
  • Os detalhes da solicitação são gravados no console, juntamente com cada Todo objeto.

Publicação HTTP

Uma POST solicitação envia dados ao servidor para processamento. O Content-Type cabeçalho da solicitação significa qual tipo MIME o corpo está enviando. Para fazer uma solicitação HTTP POST , dado um HttpClient e um Uri, use o HttpClient.PostAsync método:

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
    //   }
}

O código anterior:

  • Prepara uma StringContent instância com o corpo JSON da solicitação (tipo MIME de "application/json").
  • Faz uma POST solicitação para "https://jsonplaceholder.typicode.com/todos".
  • Garante que a resposta seja bem-sucedida e grava os detalhes da solicitação no console.
  • Grava o corpo da resposta como uma cadeia de caracteres no console.

HTTP Post como JSON

Para serializar POST automaticamente argumentos de solicitação e desserializar respostas em objetos C# fortemente tipados, use o PostAsJsonAsync método de extensão que faz parte do pacote 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 }
}

O código anterior:

  • Serializa a Todo instância como JSON e faz uma POST solicitação ao "https://jsonplaceholder.typicode.com/todos".
  • Garante que a resposta seja bem-sucedida e grava os detalhes da solicitação no console.
  • Desserializa o corpo da resposta em uma Todo instância e grava o Todo no console.

HTTP Colocar

O PUT método request substitui um recurso existente ou cria um novo usando a carga útil do corpo da solicitação. Para fazer uma solicitação HTTP PUT , dado um HttpClient e um URI, use o HttpClient.PutAsync método:

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
    //   }
}

O código anterior:

  • Prepara uma StringContent instância com o corpo JSON da solicitação (tipo MIME de "application/json").
  • Faz uma PUT solicitação para "https://jsonplaceholder.typicode.com/todos/1".
  • Garante que a resposta seja bem-sucedida e grava os detalhes da solicitação e o corpo da resposta JSON no console.

HTTP colocado como JSON

Para serializar PUT automaticamente argumentos de solicitação e desserializar respostas em objetos C# fortemente tipados, use o PutAsJsonAsync método de extensão que faz parte do pacote 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 }
}

O código anterior:

  • Serializa a Todo instância como JSON e faz uma PUT solicitação ao "https://jsonplaceholder.typicode.com/todos/5".
  • Garante que a resposta seja bem-sucedida e grava os detalhes da solicitação no console.
  • Desserializa o corpo da resposta em uma Todo instância e grava o Todo no console.

HTTP Patch

A PATCH solicitação é uma atualização parcial de um recurso existente. Não cria um novo recurso e não se destina a substituir um recurso existente. Em vez disso, atualiza um recurso apenas parcialmente. Para fazer uma solicitação HTTP PATCH , dado um HttpClient e um URI, use o HttpClient.PatchAsync método:

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
    //   }
}

O código anterior:

  • Prepara uma StringContent instância com o corpo JSON da solicitação (tipo MIME de "application/json").
  • Faz uma PATCH solicitação para "https://jsonplaceholder.typicode.com/todos/1".
  • Garante que a resposta seja bem-sucedida e grava os detalhes da solicitação e o corpo da resposta JSON no console.

Não existem métodos de extensão para PATCH solicitações no System.Net.Http.Json pacote NuGet.

Exclusão HTTP

Uma DELETE solicitação exclui um recurso existente. Uma DELETE solicitação é idempotente , mas não segura, o que significa que várias DELETE solicitações para os mesmos recursos produzem o mesmo resultado, mas a solicitação afeta o estado do recurso. Para fazer uma solicitação HTTP DELETE , dado um HttpClient e um URI, use o HttpClient.DeleteAsync método:

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
    //   {}
}

O código anterior:

  • Faz uma DELETE solicitação para "https://jsonplaceholder.typicode.com/todos/1".
  • Garante que a resposta seja bem-sucedida e grava os detalhes da solicitação no console.

Gorjeta

A resposta a um DELETE pedido (tal como um PUT pedido) pode ou não incluir um organismo.

Cabeça HTTP

O HEAD pedido é semelhante a um GET pedido. Em vez de retornar o recurso, ele retorna apenas os cabeçalhos associados ao recurso. Uma resposta ao HEAD pedido não devolve um corpo. Para fazer uma solicitação HTTP HEAD , dado um HttpClient e um URI, use o HttpClient.SendAsync método com o HttpMethod definido como 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
}

O código anterior:

  • Faz uma HEAD solicitação para "https://www.example.com/".
  • Garante que a resposta seja bem-sucedida e grava os detalhes da solicitação no console.
  • Itera em todos os cabeçalhos de resposta, gravando cada um no console.

Opções HTTP

A OPTIONS solicitação é usada para identificar quais métodos HTTP um servidor ou ponto de extremidade suporta. Para fazer uma solicitação HTTP OPTIONS , dado um HttpClient e um URI, use o HttpClient.SendAsync método com o HttpMethod definido como 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
}

O código anterior:

  • Envia uma OPTIONS solicitação HTTP para "https://www.example.com/".
  • Garante que a resposta seja bem-sucedida e grava os detalhes da solicitação no console.
  • Itera em todos os cabeçalhos de conteúdo de resposta, gravando cada um no console.

Rastreamento HTTP

A TRACE solicitação pode ser útil para depuração, pois fornece loop-back no nível do aplicativo da mensagem de solicitação. Para fazer uma solicitação HTTP TRACE , crie uma HttpRequestMessage usando o HttpMethod.Trace:

using HttpRequestMessage request = new(
    HttpMethod.Trace, 
    "{ValidRequestUri}");

Atenção

O TRACE método HTTP não é suportado por todos os servidores HTTP. Ele pode expor uma vulnerabilidade de segurança se usado de forma imprudente. Para obter mais informações, consulte Open Web Application Security Project (OWASP): Cross Site Tracing.

Manipular uma resposta HTTP

Sempre que você estiver manipulando uma resposta HTTP, você interage com o HttpResponseMessage tipo. Vários membros são usados para avaliar a validade de uma resposta. O código de status HTTP está disponível através da HttpResponseMessage.StatusCode propriedade. Imagine que você enviou uma solicitação dada a uma instância do cliente:

using HttpResponseMessage response = await httpClient.SendAsync(request);

Para garantir que o response is OK (código de status HTTP 200), você pode avaliá-lo conforme mostrado no exemplo a seguir:

if (response is { StatusCode: HttpStatusCode.OK })
{
    // Omitted for brevity...
}

Existem outros códigos de status HTTP que representam uma resposta bem-sucedida, como CREATED (código de status HTTP 201), ACCEPTED (código de status HTTP 202), NO CONTENT (código de status HTTP 204) e RESET CONTENT (código de status HTTP 205). Você também pode usar a HttpResponseMessage.IsSuccessStatusCode propriedade para avaliar esses códigos, o que garante que o código de status da resposta esteja dentro do intervalo 200-299:

if (response.IsSuccessStatusCode)
{
    // Omitted for brevity...
}

Se você precisar que a estrutura lance o HttpRequestException, você pode chamar o HttpResponseMessage.EnsureSuccessStatusCode() método:

response.EnsureSuccessStatusCode();

Esse código lança um HttpRequestException se o código de status da resposta não estiver dentro do intervalo 200-299.

Respostas de conteúdo HTTP válidas

Com uma resposta válida, você pode acessar o corpo da resposta usando a Content propriedade. O corpo está disponível como uma HttpContent instância, que você pode usar para acessar o corpo como um fluxo, matriz de bytes ou cadeia de caracteres:

await using Stream responseStream =
    await response.Content.ReadAsStreamAsync();

No código anterior, o responseStream pode ser usado para ler o corpo da resposta.

byte[] responseByteArray = await response.Content.ReadAsByteArrayAsync();

No código anterior, o responseByteArray pode ser usado para ler o corpo da resposta.

string responseString = await response.Content.ReadAsStringAsync();

No código anterior, o responseString pode ser usado para ler o corpo da resposta.

Finalmente, quando você sabe que um ponto de extremidade HTTP retorna JSON, você pode desserializar o corpo da resposta em qualquer objeto C# válido usando o pacote NuGet System.Net.Http.Json :

T? result = await response.Content.ReadFromJsonAsync<T>();

No código anterior, result é o corpo da resposta desserializado como o tipo T.

Tratamento de erros HTTP

Quando uma solicitação HTTP falha, o HttpRequestException é lançado. Capturar essa exceção por si só pode não ser suficiente, pois há outras exceções potenciais lançadas que você pode querer considerar lidar. Por exemplo, o código de chamada pode ter usado um token de cancelamento que foi cancelado antes da solicitação ser concluída. Nesse cenário, você pegaria o 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}");
}

Da mesma forma, ao fazer uma solicitação HTTP, se o servidor não responder antes que o HttpClient.Timeout seja excedido, a mesma exceção será lançada. No entanto, nesse cenário, você pode distinguir que o tempo limite ocorreu avaliando o ao capturar o Exception.InnerExceptionTaskCanceledException:

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}");
}

No código anterior, quando a exceção interna é uma TimeoutException , o tempo limite ocorreu e a solicitação não foi cancelada pelo token de cancelamento.

Para avaliar o código de status HTTP ao capturar um HttpRequestException, você pode avaliar a HttpRequestException.StatusCode propriedade:

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}");
}

No código anterior, o EnsureSuccessStatusCode() método é chamado para lançar uma exceção se a resposta não for bem-sucedida. A HttpRequestException.StatusCode propriedade é então avaliada para determinar se a resposta foi um (código de 404 status HTTP 404). Existem vários métodos auxiliares que HttpClient chamam implicitamente EnsureSuccessStatusCode em seu nome, considere as seguintes APIs:

Gorjeta

Todos os HttpClient métodos usados para fazer solicitações HTTP que não retornam uma HttpResponseMessage chamada EnsureSuccessStatusCode implícita em seu nome.

Ao chamar esses métodos, você pode manipular e HttpRequestException avaliar a HttpRequestException.StatusCode propriedade para determinar o código de status HTTP da resposta:

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}");
}

Pode haver cenários em que você precise lançar o HttpRequestException seu código. O HttpRequestException() construtor é público e você pode usá-lo para lançar uma exceção com uma mensagem personalizada:

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}");
}

Proxy HTTP

Um proxy HTTP pode ser configurado de duas maneiras. Um padrão é especificado na HttpClient.DefaultProxy propriedade. Como alternativa, você pode especificar um proxy na HttpClientHandler.Proxy propriedade.

Proxy padrão global

O HttpClient.DefaultProxy é uma propriedade estática que determina o proxy padrão que todas as HttpClient instâncias usam se nenhum proxy for definido explicitamente no passado através de HttpClientHandler seu construtor.

A instância padrão retornada por essa propriedade é inicializada seguindo um conjunto diferente de regras, dependendo da sua plataforma:

  • Para Windows: lê a configuração de proxy a partir de variáveis de ambiente ou, se estas não estiverem definidas, a partir das definições de proxy do utilizador.
  • Para macOS: lê a configuração de proxy a partir de variáveis de ambiente ou, se estas não estiverem definidas, a partir das definições de proxy do sistema.
  • Para Linux: lê a configuração de proxy de variáveis de ambiente ou, caso elas não estejam definidas, essa propriedade inicializa uma instância não configurada que ignora todos os endereços.

As variáveis de ambiente usadas para DefaultProxy inicialização em plataformas baseadas em Windows e Unix são:

  • HTTP_PROXY: o servidor proxy usado em solicitações HTTP.
  • HTTPS_PROXY: o servidor proxy usado em solicitações HTTPS.
  • ALL_PROXY: o servidor proxy usado em solicitações HTTP e/ou HTTPS caso HTTP_PROXY e/ou HTTPS_PROXY não estejam definidos.
  • NO_PROXY: uma lista separada por vírgulas de nomes de host que devem ser excluídos do proxy. Asteriscos não são suportados para curingas; Use um ponto à esquerda caso queira corresponder a um subdomínio. Exemplos: NO_PROXY=.example.com (com ponto à esquerda) corresponderá a www.example.com, mas não corresponderá a example.com. NO_PROXY=example.com(sem ponto principal) não corresponderá .www.example.com Este comportamento pode ser revisitado no futuro para corresponder melhor a outros ecossistemas.

Em sistemas onde as variáveis de ambiente diferenciam maiúsculas de minúsculas, os nomes das variáveis podem ser todos minúsculos ou maiúsculos. Os nomes minúsculos são verificados primeiro.

O servidor proxy pode ser um nome de host ou endereço IP, opcionalmente seguido por dois pontos e número de porta, ou pode ser uma http URL, opcionalmente incluindo um nome de usuário e senha para autenticação de proxy. A URL deve ser iniciada com http, não https, e não pode incluir nenhum texto após o nome do host, IP ou porta.

Proxy por cliente

A HttpClientHandler.Proxy propriedade identifica o WebProxy objeto a ser usado para processar solicitações para recursos da Internet. Para especificar que nenhum proxy deve ser usado, defina a Proxy propriedade como a instância de proxy retornada GlobalProxySelection.GetEmptyWebProxy() pelo método.

O computador local ou o arquivo de configuração do aplicativo pode especificar que um proxy padrão seja usado. Se a propriedade Proxy for especificada, as configurações de proxy da propriedade Proxy substituirão o computador local ou o arquivo de configuração do aplicativo e o manipulador usará as configurações de proxy especificadas. Se nenhum proxy for especificado em um arquivo de configuração e a propriedade Proxy não for especificada, o manipulador usará as configurações de proxy herdadas do computador local. Se não houver configurações de proxy, a solicitação será enviada diretamente para o servidor.

A HttpClientHandler classe analisa uma lista de bypass de proxy com caracteres curinga herdados das configurações do computador local. Por exemplo, a HttpClientHandler classe analisa uma lista de bypass de "nt*" navegadores como uma expressão regular de "nt.*". Assim, uma URL de http://nt.com ignoraria o proxy usando a HttpClientHandler classe.

A HttpClientHandler classe suporta bypass de proxy local. A classe considera um destino como local se qualquer uma das seguintes condições for atendida:

  1. O destino contém um nome simples (sem pontos no URL).
  2. O destino contém um endereço de loopback (Loopback ou IPv6Loopback) ou o destino contém um IPAddress atribuído ao computador local.
  3. O sufixo de domínio do destino corresponde ao sufixo de domínio do computador local (DomainName).

Para obter mais informações sobre como configurar um proxy, consulte:

Consulte também