Back-End

28 nov, 2017

Introdução ao Java 9 – HTTP2

Publicidade

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/