Java HttpClient
Faça requisições HTTP em Java moderno com java.net.http.HttpClient, incluindo suporte a chamadas síncronas, assíncronas e HTTP/2.
java.net.http.HttpClient, padronizado no Java 11, é a API HTTP moderna e a escolha certa para código novo. Ele substitui o verboso HttpURLConnection por um design imutável baseado em builder: HTTP/2 por padrão, chamadas síncronas e assíncronas nativas, e tratamento plugável de corpos de requisição e resposta. Três tipos fazem o trabalho — HttpClient, HttpRequest e HttpResponse.
Este capítulo aborda a construção e o reuso de um cliente, a construção de requisições com corpos e cabeçalhos, os modos de envio síncrono e assíncrono, como os BodyHandlers convertem uma resposta no tipo desejado, e os erros comuns que pegam usuários de primeira viagem. Se você é novo em rede em Java, comece pela introdução a redes; para o bloco de construção assíncrono usado aqui, consulte CompletableFuture.
Os três tipos
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2) // HTTP/2, falling back to 1.1
.connectTimeout(Duration.ofSeconds(10))
.followRedirects(HttpClient.Redirect.NORMAL)
.build();Um único HttpClient é thread-safe e reutilizável — construa um e compartilhe-o por toda a aplicação; não crie um por requisição. A partir dele, você envia objetos HttpRequest e recebe de volta objetos HttpResponse.
Construindo uma requisição
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api"))
.header("Accept", "application/json")
.timeout(Duration.ofSeconds(5))
.POST(HttpRequest.BodyPublishers.ofString("{\"x\":1}"))
.build();O método do verbo (GET(), POST(...), PUT(...), DELETE()) é escolhido no builder. Um BodyPublisher fornece o corpo da requisição — ofString, ofByteArray, ofFile ou noBody(). As requisições são imutáveis uma vez construídas e podem ser reutilizadas.
Envio: síncrono e assíncrono
// Blocking
HttpResponse<String> resp =
client.send(request, HttpResponse.BodyHandlers.ofString());
// Non-blocking — returns a CompletableFuture
CompletableFuture<HttpResponse<String>> future =
client.sendAsync(request, HttpResponse.BodyHandlers.ofString());Um BodyHandler decide como o corpo da resposta é materializado: ofString(), ofByteArray(), ofFile(path), ofLines() (um Stream<String>), ou discarding(). sendAsync retorna um CompletableFuture, então você encadeia .thenApply, .thenAccept e .exceptionally sem bloquear uma thread.
Lendo a resposta
HttpResponse<T> é um objeto de valor tipado simples. Os métodos mais utilizados:
statusCode()— o status HTTP comoint(ex.:200,404). Não existeisSuccessful(); verifique o código você mesmo.body()— o corpo, já convertido paraTpeloBodyHandlerpassado.headers()— umHttpHeaders. UsefirstValue("Content-Type")(retorna umOptional<String>) ouallValues("Set-Cookie")para cabeçalhos repetidos.uri()— o URI final, que pode diferir do URI da requisição após um redirecionamento.
Os nomes de cabeçalhos são comparados sem diferenciação de maiúsculas e minúsculas, portanto firstValue("content-type") e firstValue("Content-Type") retornam o mesmo valor.
Exemplo completo: GET síncrono, POST síncrono e assíncrono
Este programa serve um endpoint de loopback que reporta o método HTTP recebido, e então o aciona de três formas com um único HttpClient compartilhado: um GET síncrono, um POST síncrono com corpo, e um GET assíncrono por meio de um CompletableFuture.
O que extrair da execução:
- Um
HttpClientatendeu todas as três requisições. O cliente é imutável e thread-safe, então o padrão correto é construir uma vez e compartilhar em toda parte; criar um cliente por chamada desperdiça pools de conexão e sessões HTTP/2. Observe que não hádisconnect()em lugar algum — o cliente gerencia as conexões por você. - O verbo da requisição ficou no builder:
.GET()para leitura e.POST(BodyPublishers.ofString("payload"))para escrita. O servidor ecoou de volta o método que recebeu (handled GET,handled POST), confirmando que o publisher tanto transportou o corpo quanto definiu o verbo. HttpResponseé um objeto tipado comstatusCode()ebody(). Como umBodyHandlers.ofString()foi passado, o corpo voltou já decodificado comoString— substitua porofByteArray,ofFileouofLinese a mesma chamada retorna bytes, um arquivo salvo, ou um stream de linhas.- A chamada assíncrona retornou um
CompletableFuturee foi composta com.thenApplysem bloquear uma thread atéfuture.get(). Essa é a vantagem estrutural sobreHttpURLConnection: concorrência é embutida, portanto centenas de requisições em andamento não precisam significar centenas de threads bloqueadas. - Todo o fluxo — cliente, requisição, envios síncrono e assíncrono, respostas tipadas — não usou streams manuais nem armadilha de error-stream. Comparado com
HttpURLConnection,HttpClienté mais curto, mais seguro e mais capaz, razão pela qual é a escolha padrão no Java 11+.
Erros comuns
- Um 4xx ou 5xx não é uma exceção. Ao contrário de algumas bibliotecas,
HttpClientretorna a resposta normalmente para qualquer status recebido; somente falhas de transporte (conexão recusada, timeout, DNS) lançamIOException. Sempre inspecionestatusCode()— o corpo de uma resposta de erro ainda é legível. - Construa um cliente, compartilhe-o.
HttpClienté imutável e thread-safe e possui seu próprio pool de conexões. Criar um por requisição descarta o reuso de conexões e sessões HTTP/2. Não háclose()a chamar antes do Java 21 (e no Java 21+ ele éAutoCloseable, mas um cliente compartilhado de longa duração raramente precisa ser fechado). connectTimeoutetimeoutsão diferentes.HttpClient.connectTimeout(...)limita quanto tempo o estabelecimento da conexão TCP pode levar;HttpRequest.timeout(...)limita toda a requisição/resposta. Uma requisição que expira completa o future de forma excepcional com umHttpTimeoutException.- Um
GETnão pode carregar um corpo. ChamarGET()com umBodyPublishernão é como a API funciona — usePOST,PUTou o genéricomethod(name, publisher)para verbos que enviam dados. URI.createdeve receber um URI absoluto e bem formado. Espaços e outros caracteres inseguros não são codificados para você; codifique os parâmetros de consulta antes de construir o URI.