Esse capítulo fornece uma visão geral de como a web funciona hoje, discutindo conceitos importantes que são fundamentais para entender o resto do livro. Apesar de alguns leitores poderem ter familiaridade com o material, esse capítulo fornece uma oportunidade valiosa de revisitar o básico.
Todos os navegadores, servidores e outras tecnologias relacionadas à web falam entre si através do HTTP, ou Hypertext Transfer Protocol. O HTTP é a linguagem em comum utilizada hoje na internet.
O conteúdo da web é armazenado nos servidores que se comunicam usando o protocolo HTTP, normalmente chamados de servidores HTTP. Eles guardam os dados da Internet e os fornecem quando solicitados por clientes HTTP.
Clientes pedem pelos dados enviando requisições HTTP aos servidores. Então os servidores respondem com os dados em respostas HTTP.
A mensagem que foi enviada pelo seu navegador é chamada de Requisição ou Requisição HTTP. A mensagem recebida pelo seu navegador, que foi enviada por um servidor, é chamada de Resposta HTTP ou apenas de Resposta. Juntas, a resposta e a requisição, são chamadas de Mensagem HTTP.
Alerta: Não visite a URL mencionada acima.
Antes de introduzir mais componentes do HTTP, vamos construir um servidor HTTP básico usando Node.js.
Crie um novo projeto, coloque o nome que você quiser. Dentro do diretório, crie um novo arquivo index.js
// file: index.js
// Importa o módulo 'node:http' e o atribui à constante 'http'.
const http = require("node:http");
// Define uma função chamada 'handle_request' que recebe dois parâmetros: 'request' and 'response'.
function handle_request(request, response) {
// Envia a string "Hello world" como conteúdo da resposta.
// Não faz nada com a requisição, por agora.
response.end("Hello world");
}
// Cria um servidor HTTP usando o método 'createServer' do módulo 'http'.
// Passa a função 'handle_request' como o callback para lidar com solicitações recebidas.
const server = http.createServer(handle_request);
// Inicia o servidor para escutar requisições recebidas na porta 3000 e no host 'localhost'
server.listen(3000, "localhost");
// De maneira alternativa, você pode usar o endereço IP '127.0.0.1' ao invés de 'localhost'
server.listen(3000, "127.0.0.1");
Vamos passar pelo código acima em mais detalhes:
const http = require("node:http");
Essa linha traz o módulo http
do Node.js, que fornece funcionalidades básicas para criar servidores HTTP.
function handle_request(request, response) {
response.end("Hello world");
}
Essa função possui dois parâmetros de entrada: request
(é a mensagem que vem da internet) e response
(mensagem que enviamos de volta ao usuário). Estamos simplesmente enviando de volta um "Hello world" de resposta.
const server = http.createServer(handle_request);
Estamos criando um servidor HTTP usando o método createServer
do módulo http
. A função handle_request
é atribuída como a função callback que será chamada quando o servidor receber uma requisição.
Então, sempre que houver uma nova requisição HTTP, nossa função handle_request
será invocada e dois argumentos, request
e response
, serão fornecidos.
server.listen(3000, "localhost");
Essa linha do código inicia o servidor e o deixa disponível em http://localhost:3000
.
server.listen(3000, "127.0.0.1");
Você também pode usar o endereço IP '127.0.0.1'
ao invés de 'localhost'
para atingir o mesmo resultado.
Ambos, localhost
e 127.0.0.1
, fazem referência ao endereço loopback, o que significa que o servidor só será acessível da mesma máquina que está sendo executado. Isso é geralmente usado por desenvolvedores para fins de teste e debugging.
Na verdade, é uma boa prática desenvolver e testar aplicações localmente antes de realizar o deploy para um ambiente de produção, já que isso permite o debugging e correção de maneira mais fácil para qualquer problema que possa aparecer.
Para iniciar o servidor web, precisamos simplesmente executar o arquivo index.js
. Vamos tentar executá-lo:
$ node index
# no response, is there something wrong?
Você deve ter notado que o programa não fechou como ele costumáva fazer anteriormente, quando rodávamos nossa biblioteca de logging ou em exemplos de códigos anteriores. Esse comportamento pode ser um pouco surpreendente, mas é esperado devido à natureza do funcionamento dos servidores HTTP.
Quando executamos um servidor HTTP usando http.createServer()
, o servidor é feito para escutar por requisições recebidas de maneira indefinida. Ele não termina assim que o script termina a execução, diferente de alguns outros scripts que podem executar uma única tarefa e então encerrar.
Isso porque o propósito de um servidor HTTP é escutar continuamente por requisições recebidas e respondê-las em tempo real. Se o servidor fechasse imediatamente, ele não seria capaz de completar seu propósito de servir conteúdo aos clientes.
Para ver se o nosso servidor web está funcionando como esperado, e para ver a resposta "Hello world", precisamos primeiro fazer uma requisição. Há algumas maneiras de fazer uma requisição. Vamos pegar o caminho fácil.
Vá ao navegador de sua escolha, e visite a URL http://localhost:3000
ou http://127.0.0.1
ou localhost:3000
ou 127.0.0.1:3000
.
Sim, parece funcionar corretamente. Vamos fazer uma requisição para o nosso servidor de uma maneira diferente, para ver todas as partes necessárias que compõem uma requisição HTTP.
Abra seu terminal e digite o seguinte comando cURL
:
$ curl http://localhost:3000
Hello world%
Perfeito. cURL
é um modo rápido e conveniente de testar endpoints HTTP. É fácil de usar e não necessita ter outros clientes HTTP em execução, ou da aba do seu chrome aberta.
Vamos modificar a requisição cURL
:
$ curl http://localhost:3000 -v
Estamos especificando o argumento -v
(ou --verbose
) que exibe mais informações sobre o ciclo de vida da conexão HTTP. Essa é a saída que você obtém ao executar o comando acima:
$ curl http://localhost:3000 -v
* Trying 127.0.0.1:3000...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.87.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Wed, 23 Aug 2023 13:13:32 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Content-Length: 11
<
* Connection #0 to host localhost left intact
Hello world%
Isso é bastante coisa pra digerir. Uma coisa a ser notada são os dois diferentes operadores utilizados - >
e <
. A flecha >
indica que isso está sendo enviado como uma requisição pelo cliente. O cliente aqui se refere ao cURL
no seu terminal. A flecha <
indica que essas linhas foram recebidas como uma resposta do servidor.
Vamos dar uma olhada nisso linha por linha:
Trying 127.0.0.1:3000...
Essa linha está indicando que cURL
está tentando estabilizar uma conexão com o endereço IP 127.0.0.1. Esse endereço IP também é conhecido como localhost e se refere ao computador local no qual você está trabalhando atualmente.
A conexão está sendo feita na porta número 3000, que é um número usado para identificar um processo específico no qual os dados são enviados ou recebidos. Vamos falar sobre PORTs (portas) no próximo capítulo.
Connected to localhost (127.0.0.1) port 3000 (#0)
Isso significa que a conexão ao endereço IP e porta especificados foram estabilizados com sucesso. Essa é uma boa notícia e significa que você pode prosseguir com sua tarefa sem mais demora.
O (#0) na mensagem se refere ao index (índice) da conexão. Isso é uma informação útil, especialmente se você está fazendo múltiplas conexões ao mesmo tempo. Ao monitorar o index da conexão, você consegue evitar qualquer confusão ou erro que possa aparecer ao misturar diferentes conexões.
> GET / HTTP/1.1
O cURL
está enviando uma requisição HTTP ao servidor utilizando o método GET
. A /
depois do método indica que a requisição está sendo feita para o path raiz, ou o endpoint root (raiz) do servidor.
> Host: localhost:3000
Essa linha especifica que o comando cURL
está definindo o cabeçalho Host
na requisição, que diz ao servidor o nome do domínio e a porta da requisição.
> User-Agent: curl/7.87.0
Essa linha também faz parte dos cabeçalhos da requisição HTTP. Inclui o cabeçalho User-Agent
, que identifica o cliente fazendo uma requisição. Neste caso, indica que a requisição está sendo feita utilizando curl
versão 7.87.0.
> Accept: */*
Essa linha define o cabeçalho Accept
, que diz ao servidor que tipos de conteúdo-resposta os clientes podem lidar. Nesse caso, indica que o cliente aceita qualquer tipo de conteúdo.
>
Essa linha indica o fim dos cabeçalhos de requisição HTTP. Uma linha vazia como essa separa os cabeçalhos do corpo da requisição, que não está presente nesse caso por ser uma requisição GET
. Vamos falar sobre o POST
e outros verbos/métodos http nos capítulos a seguir.
Mark bundle as not supporting multiuse
Essa é uma mensagem de log interna do curl
e não tem um impacto direto na interpretação da requisição ou da resposta. Está relacionado a como o curl
gerencia múltiplas conexões em uma sessão.
< HTTP/1.1 200 OK
Essa linha é parte da resposta HTTP. Indica que o servidor respondeu com um código de status HTTP 200 OK
, o que significa que a requisição foi bem sucedida. De novo, vamos entender os códigos de status HTTP no próximo capítulo. Por agora, é o suficiente imaginar que qualquer código de status na forma 2xx
, onde x é um número, significa que está tudo bem.
< Date: Wed, 23 Aug 2023 13:13:32 GMT
Essa linha faz parte dos cabeçalhos de resposta HTTP. Uma coisa importante a notar, esse é o cabeçalho definido pelo servidor e não pelo cliente. Inclui o cabeçalho Date
, que indica a data e hora de quando a resposta foi gerada no servidor.
< Connection: keep-alive
Essa linha faz parte dos cabeçalhos de resposta e informa ao cliente que o servidor deseja manter uma conexão persistente, e reutilizar a conexão para requisições futuras em potencial. Isso ajuda com a performance.
< Keep-Alive: timeout=5
Essa linha, também pertencente aos cabeçalhos de resposta, especifica o tempo (5 segundos neste caso) que o servidor manterá a conexão ativa se nenhuma solicitação adicional for feita.
< Content-Length: 11
Essa linha indica o tamanho do conteúdo da resposta em bytes. Nesse caso, o corpo da resposta tem um comprimento de 11 bytes.
<
Essa linha marca o fim dos cabeçalhos de resposta e o início do corpo da resposta.
Connection #0 to host localhost left intact
Essa linha é uma mensagem de log do curl
indicando que a conexão com o servidor está sendo deixada aberta (intact
) e não foi fechada imediatamente depois de receber a resposta. Ela poderia ser potencialmente reutilizada para requisições subsequentes.
Hello world%
Esse é o corpo real da resposta retornada pelo servidor. Nesse caso, é uma simples string de texto dizendo "Hello world". O %
não é nada para se preocupar. Indica que a resposta não termina com um caracter \n
.
Agora que entendemos quais são os componentes básicos da requisição
e da resposta
, vamos entender esses componentes em mais detalhes, no próximo capítulo