O módulo que mais gostei no Java 9 foi o de HTTP2. Por mais que seja um módulo não oficial (incubação, há diversas utilidades: é menos profuso para criar requisições, tem mais recursos para as respostas da requisição e o mais interessante, a requisição assíncrona. Em um pequeno resumo do HTTP2, os headers são binários e comprimidos usando Hpack, o que diminui o volume de dados trafegados. Há dezenas de recursos na web comum hoje, como imagens, arquivos, js, etc. E cada recurso é um request.
Para complicar mais ainda, o HTTP 1.1 é um protocolo sequencial que enfileira requisições. Para resolver o problema, no HTTP2, requisições e respostas são paralelas em uma única conexão automaticamente. O protocolo na sua versão 1.1 passa ser stateful que mantém o estado conversacional, mas a sua estética permanece stateless, não tem nenhuma informação das requisições anteriores.
HTTP/2 Client API
Para utilizar uma API em fase de incubação, você vai precisar passar a opção –add-modules com o seu namespace que, no caso do Http/2 Client, é o jdk.incubator.httpclient. Essa opção funciona da mesma forma caso você opte por utilizar o JShell, ferramenta de linha de comando do JDK. Para saber mais sobre JShell, tem o artigo do Bruno aqui. Um dos problemas de requisições Java da forma antiga é a sua verbosidade e seu uso bloqueante (enfileira requisições) era uma thread por requisição e resposta.
Requests HTTP de forma antiga no Java
<pre class="lang:default decode:true "> URLConnection urlConnection = url.openConnection(); BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); String line; while((line = reader.readLine()) != null){ System.out.println(line); } reader.close(); </pre>
No novo módulo HTTP/2
A principal informação que você tem que saber sobre essa mudança são as classes abstratas nas quais a nova API lida com as conexões HttpClient, HttpRequest e HttpResponse. Sendo a principal, a HttpClient, como a responsável por criar e enviar requisições.
HttpClient -> HttpRequest -> HttpResponse -> HttpClient
Segue um código de exemplo abaixo:
<pre class="lang:default decode:true "> HttpClient httpClient = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build(); HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandler.asString()); System.out.println(“http version: “ + response.version() + “status code: ” + response.statusCode() + “content: “ + response.body()); </pre> Linha1: HttpClient.newHttpClient() : cria uma nova conexão. Linha 2: HttpRequest.newBuilder().uri(“passa o endereço”).GET().build(): Devolve HttpRequest a necessidade principal é passar uma url e o verbo http, no exemplo é GET Linha 3: httpClient.send() : faz o envio da requisição.
Requisições Assíncronas
No exemplo acima, utilizamos o método httpClient.send(…) que funciona de forma síncrona. Na nova API você consegue enviar requisições assíncronas facilmente. O processo fica executando em background, enquanto a thread principal fica livre para executar outras tarefas.
Para fazer o uso, no lugar do método send, utilizamos sendAsync: httpClient.sendAsync(request, ….). O que difere entre a requisição assíncrona é o seu retorno, pois é retornado um CompletableFuture que vai nos informar quando essa resposta vai estar pronta para o uso. Com o CompletableFuture, podemos verificar se a requisição está pronta com o isDone, imprimindo a saída da resposta ou cancelando a requisição.
<pre class="lang:default decode:true "> if(response.isDone()){ System.out.println(response.get().body()); }else{ System.out.println(“Cancelando a requisição”); response.cancel(true); } </pre>
Outra forma de trabalhar com o CompletableFuture, seria adicionando um callBack e quando a requisição ficar pronta, imprimir a saída.
<pre class="lang:default decode:true "> response.whenComplete((r,t) -> System.out.println(r.body())) </pre>
Exemplo de requisição Assíncrona:
<pre class="lang:default decode:true "> HttpClient.newHttpClient().sendAsync(HttpRequest.newBuilder() .uri(new URI("https://google.com.br")).GET().build(), HttpResponse.BodyHandler.asString())) .whenComplete((r,t) -> System.out.println("arquivo salvo em: " + r.body().toAbsolutePath())); </pre>
O módulo HTTP/2 Client do Java 9 é grande, tem muitos detalhes que podem ser lidos na documentação. Neste artigo eu destaquei pontos principais da utilização.
***
Este artigo foi publicado originalmente em: https://www.concrete.com.br/2017/11/13/introducao-ao-java-9-http-2/