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:
- https://jsonplaceholder.typicode.com: API falsa gratuita para testes e prototipagem.
- https://www.example.com: Este domínio destina-se a ser utilizado em exemplos ilustrativos em documentos.
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 umastatic
variável. De acordo com as diretrizes, recomenda-se reutilizarHttpClient
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:
- Configuração HttpClient.DefaultRequestHeaders.
- Aplicando um não-padrão HttpClient.Timeout.
- Especificando o HttpClient.DefaultRequestVersionarquivo .
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 oSendAsync
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.
Nota
Ao segmentar dispositivos Android (como com o desenvolvimento do .NET MAUI), você deve adicionar android:usesCleartextTraffic="true"
ao <application></application>
AndroidManifest.xml. Isso permite o tráfego de texto não criptografado, como solicitações HTTP, que de outra forma é desativado por padrão devido às políticas de segurança do Android. Considere o seguinte exemplo de configurações XML:
<?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 obter mais informações, consulte Habilitar tráfego de rede de texto não criptografado para o domínio localhost.
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
, PUT
e 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).
- ByteArrayContent: Fornece conteúdo HTTP com base em uma matriz de bytes.
- FormUrlEncodedContent: Fornece conteúdo HTTP para tuplas de nome/valor codificadas usando
"application/x-www-form-urlencoded"
o tipo MIME. - JsonContent: Fornece conteúdo HTTP baseado em JSON.
- MultipartContent: Fornece uma coleção de objetos HttpContent que são serializados usando a especificação de
"multipart/*"
tipo MIME. - MultipartFormDataContent: Fornece um contêiner para conteúdo codificado usando
"multipart/form-data"
o tipo MIME. - ReadOnlyMemoryContent: Fornece conteúdo HTTP com base em um ReadOnlyMemory<T>arquivo .
- StreamContent: Fornece conteúdo HTTP com base em um fluxo.
- StringContent: Fornece conteúdo HTTP com base em uma cadeia de caracteres.
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 umaPOST
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 oTodo
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 umaPUT
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 oTodo
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.InnerException 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}");
}
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 casoHTTP_PROXY
e/ouHTTPS_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á awww.example.com
, mas não corresponderá aexample.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:
- O destino contém um nome simples (sem pontos no URL).
- O destino contém um endereço de loopback (Loopback ou IPv6Loopback) ou o destino contém um IPAddress atribuído ao computador local.
- 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: