Adicionando HTML

Na última seção construímos a primeira versão do nosso simples HTTP server, que envia uma mensagem PONG em plain text.

Mas como estamos falando de Web, seria mais adequado enviarmos HTML no body, não?

Vamos modificar o server para responder um content-type header text/html, indicando que o client deve saber renderizar HTML, bem como fazendo com que o body seja um parágrafo HTML, no caso colocando a palavra PONG dentro da HTML tag <p>.

## Server
$ echo -e "HTTP/1.1 200\r\n\
Content-Type: text/html\r\n\
\r\n\
<p>PONG</p>" | nc -lvN 8080

Listening on 0.0.0.0 8080

Do lado do client, não precisamos mais de body. Podemos, por exemplo, indicar que queremos uma rota/caminho para o recurso /ping, deixando assim nossa comunicação HTTP mais semântica.

## Client
$ echo -e "GET /ping HTTP/1.1\r\n\
Content-Type: text/html\r\n\
\r\n" | nc -v localhost 8080

HTTP/1.1 200
Content-Type: text/html

<p>Hello</p>

Podemos ver que, apesar do HTTP header indicar que o tipo do conteúdo é HTML, o comando netcat do lado do client não sabe renderizar.

Isto porque, para renderizar HTML, é preciso ter um motor de renderização, coisa que os Web browsers implementam. Vamos experimentar outros HTTP clients.

Outros HTTP clients

Vamos começar com curl, que é um HTTP client muito utilizado para testes e automação na linha de comando do terminal:

## Client
$ curl localhost:8080/ping
<p>Hello</p>

Interessante. Podemos ver que o programa curl sabe interpretar uma mensagem HTTP, mas não sabe renderizar HTML pois não é um Web browser.

Então é hora de testar no browser.

Super Yay! Por isto é chamado de Web browser, correto? Vamos também olhar o request que o browser mandou para o server:

GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8
Sec-GPC: 1
Accept-Language: en-GB,en
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br

Podemos reparar que a mensagem HTTP request tem o mesmo padrão que estávamos utilizando, com a diferença que o web browser adiciona muito mais HTTP headers para um melhor controle entre client e server.

Basta um web server saber ler e lidar com tais HTTP headers, enviar outros headers relevantes de volta no response e pronto, temos uma melhor experiência de utilização para os usuários de websites, tudo contemplado no padrão HTTP!

Estado da conexão no HTTP

Importante destacar que, até o momento, tudo o que temos visto foi uma mensagem caminhar do cliente para o servidor (request), outra mensagem caminhar do servidor para o client (response) e então o server terminar o processo.

O quê está acontecendo com a conexão?

HTTP é stateless por padrão

Como HTTP se posiciona na camada de Aplicação do TCP/IP, a informação que cliente e servidor trocam está sendo transportada via TCP.

Em cada comunicação request-response é criada uma nova conexão TCP. Com isso, quando um cliente faz um pedido HTTP qualquer ao servidor e este responde, a conexão é encerrada e não há qualquer estado HTTP entre diferentes conexões TCP.

Podemos então resumir o fluxo:

  1. Client inicia conexão TCP como server

  2. Client envia um request HTTP através da conexão

  3. Server recebe a mensagem, processa e envia uma resposta HTTP

  4. Server encerra a conexão com o client

Entender este fluxo é importante para compreendermos as limitações do HTTP por ser stateless (sem estado). Em futuras seções, vamos explorar formas de mitigar esta limitação para que possamos simular uma característica stateful (com estado).

Last updated