Server HTTP con Vert.x

Dopo aver mostrato nell’articolo Server TCP con Vert.x come realizzare un server TCP con Vert.x, proseguiamo la serie sul framework implementando un server ed un client HTTP. Come sarà evidente nel seguito la modalità di utilizzo del framework a tale scopo è molto simile a quella vista nel caso del server TCP. Le versione del protocollo HTTP supportati sono HTTP/1.0, HTTP/1.1 e HTTP/2, con stile di programmazione molto simili. In particola per la versione 2 vertx supporta sia la versione basata su TSL (h2) che quella basata su TCP (h2c).

Creiamo quindi un progetto Maven ed inseriamo nel pom.xml la dipendenza al framework:

Implementazione del Server HTTP

Analogamente al caso TCP, procediamo creando la classe MainHttpServer() ed implementando i tre step di:

  1. Creazione e configurazione del server HTTP;
  2. Definizione dell’handler di gestione delle richieste;
  3. Avvio del server.

Creazione e Configurazione del Server

Per istanziare il server HTTP è sufficiente invocare il metodo createHttpServer() sull’istanza Vertx, eventualmente configurandolo con un oggetto di tipo HttpServerOptions:

In particolare per abilitare la versione 2 del protocollo HTTP è sufficiente specificare le seguenti opzioni:

in cui il metodo setUseAlpn() abilita il protocollo ALPN (Application-Layer Protocol Negotiation) che è un’estensione di TLS che negozia il protocollo prima che il client e il server inizino a scambiarsi i dati.

Gestione delle Request

Successivamente definiamo un handler che dovrà gestire la comunicazione nel momento in cui una nuova connessione viene aperta. A tale scopo la classe HttpServer fornisce il metodo  requestHandler():

L’handler riceve in input on oggetto di tipo HttpServerRequest che consente di interagire con la request HTTP, ad esempio per recuperare l’URI, il path i parametri di invocazione, gli header, etc. Inoltre il body della request può essere letto registrando un handler sulla request che sarà invocato dal framework ad ogni chunk (pezzetto) di contenuto ricevuto. La necessità dell’utilizzo di un handler per il body è dovuto al fatto che l’handler della request è invocato non appena la connessione è stabilita e gli header sono stati ricevuti dal server, ed in tale istante il body non è ancora disponibile.

Se si ha la necessità di collezionare tutto il body in memoria prima della sua elaborazione il programmatore ha due possibilità. La prima è quella di utilizzare un buffer in memoria in cui i diversi chunk saranno appesi ad ogni invocazione dell’handler. In tale caso il framework mette a disposizione un nuovo metodo  endHandler() che consente di registrare un handler invocato al termine della ricezione di tutto il body.

La seconda possibilità è di lasciar fare questa operazione al framework ed utilizzare direttamente il metodo bodyHandler() che questa volta consente di registrare un handler invocato solamente quando tutto il body è ricevuto.

Avvio del Server

Infine dobbiamo avviare il server TCP invocando il metodo listen(). Ancora una volta è possibile definire un handler per determinare l’esito dell’operazione, che altrimenti non ci sarebbe noto.

Test di Connessione

Facciamo un test eseguendo il progetto e successivamente inserendo in un browser l’url http://localhost:9090/httpvertx?q=1&q=2. Sulla console troveremo stampata la richiesta inviata dal browser:

Invio della Risposta

Dall’oggetto HttpServerRequest è possibile estrarre l’oggetto HttpServerResponse, da utilizzare per inviare una risposta al client, attraverso l’invocazione del metodo response(). Di default lo status code restituito al client è 200 ma se necessario, ad esempio in caso di errore, è possibile indicare un codice differente mediante il metodo setStatusCode(). Inoltre con il metodo setStatusMessage() è anche possibile specificare un messaggio personalizzato di risposta. Se non si ha necessità di inviare un body al client è possibile poi utilizzare il metodo end() per chiudere e terminare la comunicazione.

Diversamente se si vuole inviare un contenuto nel body come risposta al client è necessario innanzitutto valorizzare l’header “Content-Length” e poi inviare il metodo write(). In alternativa possiamo utilizzare il chunking HTTP per frammentare un contenuto particolarmente lungo e del quale non si ha a priori conoscenza della lunghezza.

Implementazione del Client HTTP

Creiamo la classe MainHttpClient ed il relativo metodo main(). Utilizziamo quindi il metodo createHttpClient() dell’istanza Vertx per generare un oggetto di tipo HttpClient che configureremo attraverso un oggetto HttpClientOptions.

Tra le varie opzioni di configurazione disponibili i metodo setDefaultHost() e setDefaultPort() consentono di non dover specificare ad ogni invocazioni l’host e la porta di connessione.

L’oggetto HttpClient implementa tanti metodi quanti sono i principali metodi HTTP, ovvero un metodo get() per HTTP GET, uno put() per HTTP PUT, uno post() per il HTTP POST, e così via. E’ possibile però utilizzare anche un metodo generico request() che richiederà però di specificare il metodo HTTP desiderato.

Infine è possibile inserire contenuto alla request valorizzando innanzitutto l’header content-length (a meno che non si utilizzi il chunk, come visto sopra) e quindi utilizzando il metodo write().

Una volta avviate le due classi MainHttpServerMainHttpClient sulla console del server verrà stampato:

Codice Sorgente

Il codice sorgente con tutti gli esempi mostrati è scaricabile qui vertx-http.

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

As you found this post useful...

Follow us on social media!