A arquitetura Cliente-Servidor e o protocolo HTTP
Published: 2023-07-25 19:04:41

## Tópicos
&nbsp;1. [Tópicos](#t%C3%B3picos)
&nbsp;2. [Protocolo HTTP](#protocolo-http)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.1. [Stateless](#stateless)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.2. [Estrutura](#estrutura)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.3. [Requisições HTTP](#requisi%C3%A7%C3%B5es-http)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a. [GET](#get)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b. [POST](#post)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c. [PUT](#put)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d. [DELETE](#delete)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.4. [Respostas HTTP](#respostas-http)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a. [JSON](#json)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b. [XML](#xml)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c. [HTML](#html)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.5. [Arquivos](#arquivos)
&nbsp;3. [MIME-Type em Responses](#mimetype-em-responses)
&nbsp;4. [URI vs. URL](#uri-vs-url)
&nbsp;5. [Bônus - o cliente Curl: Uma Ferramenta Versátil para Requisições HTTP](#b%C3%B4nus-o-cliente-curl-uma-ferramenta-vers%C3%A1til-para-requisi%C3%A7%C3%B5es-http)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.1. [Exemplos de Uso do Curl:](#exemplos-de-uso-do-curl)
&nbsp;6. [Conclusão](#conclus%C3%A3o)

## Introdução

Partindo do princípio que o leitor tem noções gerais de rede de computadores e conhecimento sobre a comunicação entre dispositivos através das redes e sabe o que é um protocolo de comunicação, este artigo trata sobre a arquitetura cliente-servidor e o protocolo HTTP.

A arquitetura cliente-servidor é um modelo de comunicação muito utilizado em sistemas distribuídos e aplicações web. Nesse modelo, o sistema é dividido em duas partes principais: o cliente e o servidor. O cliente é responsável por fazer solicitações ao servidor e processar as respostas recebidas. Já o servidor é responsável por receber as solicitações do cliente, processá-las e enviar as respostas de volta ao cliente.

A comunicação entre o cliente e o servidor na Web é geralmente realizada através do protocolo HTTP (Hypertext Transfer Protocol), que é amplamente utilizado na internet para a transferência de dados entre clientes e servidores.

## Protocolo HTTP

O protocolo HTTP é baseado no modelo requisição-resposta, onde o cliente envia uma requisição ao servidor e o servidor responde com os dados solicitados ou um código de status indicando o resultado da operação.

É um protocolo baseado em texto (apesar de poder transportar dados binários) e utiliza o TCP (Transmission Control Protocol) como protocolo de transporte. O TCP é um dos principais protocolos da camada de transporte do modelo TCP/IP e é responsável por garantir uma comunicação confiável entre os dispositivos.

Ao utilizar o TCP como protocolo de transporte, o HTTP pode contar com mecanismos como confirmações de recebimento (ACKs), retransmissão de pacotes perdidos e controle de fluxo para garantir que os dados sejam entregues de forma confiável e em ordem.

O uso do TCP torna o HTTP uma escolha robusta para a transferência de dados na internet, especialmente para aplicações que exigem alta confiabilidade e precisão na entrega de informações.

### Stateless

O protocolo HTTP (Hypertext Transfer Protocol) é considerado stateless, o que significa que cada requisição enviada pelo cliente ao servidor é tratada de forma independente e não contém informações sobre ações anteriores. Em outras palavras, o servidor não mantém informações sobre o estado da sessão ou interação com o cliente entre as requisições.

Algumas informações importantes sobre protocolos stateless:

- Cada requisição é tratada de forma independente.
- Não há armazenamento de informações de estado entre requisições.
- O servidor não mantém informações sobre as ações anteriores do cliente.
- A comunicação é mais simples e leve, pois não há necessidade de manter uma conexão contínua entre o cliente e o servidor.
- É mais escalável, pois cada requisição pode ser processada de forma isolada e distribuída entre diferentes servidores.

Essa natureza stateless do HTTP tem implicações importantes para o desenvolvimento de aplicações web. Como o servidor não mantém informações sobre o estado da sessão, todas as informações relevantes devem ser incluídas na própria requisição, geralmente através de cabeçalhos ou parâmetros na URL. Isso permite que o servidor trate cada solicitação de forma independente, tornando a comunicação mais simples e previsível.

Por outro lado, aplicações que exigem uma comunicação mais complexa e interativa, como sistemas de autenticação ou carrinhos de compras em e-commerce, podem enfrentar desafios adicionais ao trabalhar com o HTTP stateless. Nesses casos, podem ser necessárias técnicas adicionais, como o uso de cookies ou tokens, para manter informações de estado entre as requisições. Falaremos sobre isso em outros artigos futuros.

### Estrutura

Uma requisição HTTP consiste em uma série de linhas de texto, separadas por `\n`, que delimita uma linha. A requisição tem uma linha inicial contendo o método da requisição, o caminho do recurso desejado e a versão do protocolo, seguida por cabeçalhos opcionais e o corpo da requisição (opcional em algumas situações).

Exemplo de uma requisição HTTP:

```
GET /pagina.html HTTP/1.1
Host: www.exemplo.com
User-Agent: Mozilla/5.0
```


Uma resposta HTTP também consiste em uma linha inicial contendo a versão do protocolo, o código de status e uma frase descritiva, seguida por cabeçalhos opcionais e o corpo da resposta (opcional em algumas situações).

Exemplo de uma resposta HTTP:

```
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234

<html>
<head>
<title>Página de Exemplo</title>
</head>
<body>
...
</body>
</html>
``` 


Os cabeçalhos do protocolo HTTP são bastante numerosos, além de poderem ser definidos pela aplicação (ou seja, uma aplicação pode adicionar cabeçalhos não-padrões), tanto na requisição quanto na resposta. Para mais informações sobre os cabeçalhos http, vale dar uma olhada na [página de cabeçalhos do HTTP do MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)

A seguir, vamos detalhar um pouco mais a requisição (*request*) e a resposta (*response*) de mensagens deste protocolo.

---

### Requisições HTTP

As requisições HTTP são a base da interação entre cliente e servidor na arquitetura cliente-servidor. Cada requisição é composta por um método, um caminho (URI – falaremos mais adiante sobre URI e URL) e uma versão do protocolo – esta é a primeira linha da requisição. Além disso, as requisições podem incluir cabeçalhos e um corpo com dados adicionais.

A definição do protocolo HTTP em sua versão mais usada atualmente (1.1) é feita na [RFC 2616](https://www.rfc-editor.org/rfc/rfc2616) (um documento que vale muito a leitura) e define os seguintes métodos para o HTTP:

- OPTIONS
- GET
- HEAD
- POST
- PUT
- DELETE
- TRACE
- CONNECT

Apesar disso, alguns métodos são mais utilizados e serão explicados melhor a seguir.

#### GET

O método GET é usado para solicitar a recuperação de um recurso específico no servidor. Ele envia os parâmetros na URL, geralmente na forma de cadeias de consulta (query strings). Este é o método mais utilizado na Web, pois é com ele que os *browsers* fazem a requisição para os servidores.

Exemplo de requisição GET:

```
GET /pagina.html?parametro1=valor1&parametro2=valor2 HTTP/1.1
Host: www.exemplo.com
```


Neste exemplo, apenas um cabeçalho extra está sendo enviado (`Host: www.exemplo.com`), a URI é `/pagina.html` e os parâmetros, enviados após o sinal de interrogação (`?`) são `parametro1=valor1` e `parametro2=valor2`. Note também que, por ser uma requisição que utiliza o método `GET`, não há uma linha em branco após os cabeçalhos, já que este método não suporta um corpo adicional.

#### POST

O método POST é usado para enviar dados ao servidor, geralmente para criar um novo recurso ou enviar informações sensíveis, como senhas ou dados de formulários.

Exemplo de requisição POST:

```
POST /criar_usuario HTTP/1.1
Host: www.exemplo.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 27

nome=João&email=joao@example.com
```


Neste exemplo, alguns cabeçalhos extras estão sendo incluídos (`Host: www.exemplo.com`, `Content-Type: application/x-www-form-urlencoded` e `Content-Length: 27`). Note que após os cabeçalhos há uma linha em branco (ou seja, duas quebras de linha seguidas – `\n\n`). Esta linha indica ao servidor que receberá esta requisição que o cabeçalho do protocolo está terminado, e que todo dado que ainda for enviado fará parte do corpo. O cabeçalho `Content-Length` indica quantos bytes o servidor deve esperar no corpo.

#### PUT

O método PUT é usado para enviar dados ao servidor para criar ou atualizar um recurso específico.

Exemplo de requisição PUT:

```
PUT /atualizar_usuario/123 HTTP/1.1
Host: www.exemplo.com
Content-Type: application/json
Content-Length: 47

{"nome": "Maria", "email": "maria@example.com"}
```


Neste exemplo, o tipo cabeçalho `Content-Type` avisa ao servidor que os dados enviados estão no formato `application/json`, e por conta disso é possível notar que o corpo da requisição contém dados em JSON (formato que será mais explorado adiante).

#### DELETE

O método DELETE é usado para solicitar a exclusão de um recurso específico no servidor.

Exemplo de requisição DELETE:

```
DELETE /excluir_usuario/456 HTTP/1.1
Host: www.exemplo.com
```


---

### Respostas HTTP

As respostas HTTP são enviadas pelo servidor como resposta às requisições feitas pelo cliente. Cada resposta é composta por uma linha inicial contendo o código de status e a versão do protocolo, seguida pelos cabeçalhos e o corpo com os dados solicitados (se aplicável).

Os códigos de status são usados para indicar o resultado da requisição. Eles são divididos em classes numéricas que indicam o tipo de resposta. Alguns dos códigos de status mais comuns são:

2xx: Indica que a requisição foi bem sucedida, como por exemplo "OK" (200) ou "Created" (201).
3xx: Indica redirecionamento, como por exemplo "Found" (302).
4xx: Indica erros do cliente, como por exemplo "Not Found" (404) ou "Unauthorized" (401).
5xx: Indica erros no servidor, como por exemplo "Internal Server Error" (500).

O conteúdo das respostas podem ser de diversos tipos. A seguir, vamos falar um pouco sobre os mais comuns em aplicações web mais simples.

#### JSON

O JSON (JavaScript Object Notation) é um formato leve e amplamente utilizado para troca de dados entre cliente e servidor. Ele é fácil de ler e escrever para humanos e fácil de analisar e gerar para máquinas. Sua especificação pode ser acessada [no site oficial, json.org](https://www.json.org/json-en.html).

Exemplo de resposta com JSON:

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 56

{"nome": "João", "idade": 30, "email": "joao@example.com"}
```


Note que na resposta, após a linha inicial da resposta, existem alguns cabeçalhos (`Content-Type: application/json` e `Content-Length: 56`), e logo após uma linha em branco. Assim como na requisição, esta linha em branco indica ao cliente que está recebendo a resposta que acabaram os cabeçalhos, e que o que vem a seguir é o conteúdo (corpo) da resposta.

#### XML

O XML (eXtensible Markup Language) é outra opção para troca de dados entre cliente e servidor. Ele é mais verboso que o JSON, mas também é amplamente suportado e estruturado.

Exemplo de resposta com XML:

```
HTTP/1.1 200 OK
Content-Type: application/xml
Content-Length: 143

<usuario>
    <nome>João</nome>
    <idade>30</idade>
    <email>joao@example.com</email>
</usuario>
```


#### HTML
O HTML é usado para definir a estrutura e o layout de páginas web. As respostas HTML são renderizadas pelos navegadores para exibir conteúdo aos usuários.

Exemplo de resposta com HTML:

```
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234

<!DOCTYPE html>
<html>
<head>
    <title>Página de Exemplo</title>
</head>
<body>
    <h1>Olá, mundo!</h1>
</body>
</html>
```


### Arquivos

As respostas também podem conter arquivos binários, como imagens, vídeos, documentos, etc. Nesses casos, o servidor define o cabeçalho `Content-Type` apropriado para indicar o tipo de arquivo.

Exemplo de resposta com arquivo:

```
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 45678

<dados binários do arquivo>
```


Neste exemplo, o `Content-Type` do cabeçalho está informando ao cliente que o corpo da resposta tem os dados binários de uma imagem no formato JPG. Considerando a importância de conhecer este cabeçalho, vamos falar um pouco mais sobre ele.

---

## MIME-Type em Responses

O MIME-Type (Multipurpose Internet Mail Extensions) é um tipo de dado que indica o formato e o tipo de conteúdo presente em uma resposta HTTP. Ele é especificado através do cabeçalho `Content-Type`. O MIME-Type é essencial para que o cliente saiba como interpretar e processar o conteúdo da resposta corretamente.

Por exemplo, o `Content-Type` pode ser definido como `application/json` para indicar que a resposta contém dados no formato JSON, ou como `text/html` para indicar que a resposta é uma página HTML, ou `text/css` para indicar que a resposta trata-se de um arquivo de folha de estilos CSS.

Você pode encontrar mais informações sobre os diferentes tipos de MIME-Type no [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types).

---

## URI vs. URL

URI (Uniform Resource Identifier) e URL (Uniform Resource Locator) são conceitos relacionados, mas não idênticos.

Uma URI é uma sequência compacta de caracteres que identifica um recurso abstrato ou físico, que pode ser um documento, imagem, serviço, etc. A URI é uma terminologia genérica que inclui URLs e URNs (Uniform Resource Names).

Uma URL é um tipo específico de URI que fornece os meios para localizar um recurso através de sua representação como uma sequência de caracteres. A URL inclui o esquema (como HTTP ou FTP), o domínio ou endereço IP, a porta, o caminho e os parâmetros.

Em resumo, toda URL é uma URI, mas nem toda URI é uma URL. Por exemplo, a URI urn:isbn:0451450523 identifica unicamente um livro pelo seu número ISBN, mas não é uma URL, pois não indica como acessar o recurso.

Para mais informações sobre URI e URL, você pode consultar [o artigo da Wikipedia](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier).

---


## Bônus - o cliente Curl: Uma Ferramenta Versátil para Requisições HTTP

O curl é uma ferramenta de linha de comando amplamente utilizada para fazer requisições HTTP e interagir com diversos tipos de serviços na web. Com ele, é possível realizar operações como enviar dados para APIs, realizar testes de conectividade e até mesmo baixar arquivos. A versatilidade e simplicidade do curl o tornam uma escolha popular entre desenvolvedores e administradores de sistemas.

### Exemplos de Uso do Curl:

**Requisição GET para uma API de Teste: JSONPlaceholder**

A JSONPlaceholder é uma API de teste que fornece dados fictícios em formato JSON para fins de desenvolvimento e teste. Vamos usar o curl para fazer uma requisição GET para a rota "/users/1" e obter os dados do usuário com id `1`.

```bash
curl https://jsonplaceholder.typicode.com/users/1
```

Podemos também adicionar o argumento `-v` para que o Curl exiba também os cabeçalhos, tanto do request quanto do response:

```bash
curl -v https://jsonplaceholder.typicode.com/users/1
```

Nesse caso, a resposta será algo como

```
> GET /users/1 HTTP/2
> Host: jsonplaceholder.typicode.com
> user-agent: curl/7.88.1
> accept: */*
> 
< HTTP/2 200 
< date: Tue, 25 Jul 2023 18:29:21 GMT
< content-type: application/json; charset=utf-8
< content-length: 509
< x-powered-by: Express
< x-ratelimit-limit: 1000
< x-ratelimit-remaining: 998
< x-ratelimit-reset: 1689692921
< vary: Origin, Accept-Encoding
< access-control-allow-credentials: true
< cache-control: max-age=43200
< pragma: no-cache
< expires: -1
< x-content-type-options: nosniff
< etag: W/"1fd-+fao8fhs8ofnuo93no"
< via: 1.1 vegur
< cf-cache-status: HIT
< age: 160
< accept-ranges: bytes
< nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
< server: cloudflare
< alt-svc: h3=":443"; ma=86400
< 
{
  "id": 1,
  "name": "Leanne Graham",
  "username": "Bret",
  "email": "Sincere@april.biz",
  "address": {
    "street": "Kulas Light",
    "suite": "Apt. 556",
    "city": "Gwenborough",
    "zipcode": "92998-3874",
    "geo": {
      "lat": "-37.3159",
      "lng": "81.1496"
    }
  },
  "phone": "1-770-736-8031 x56442",
  "website": "hildegard.org",
  "company": {
    "name": "Romaguera-Crona",
    "catchPhrase": "Multi-layered client-server neural-net",
    "bs": "harness real-time e-markets"
  }
* Connection #0 to host jsonplaceholder.typicode.com left intact
}
```


Note que as primeiras linhas começam com o caracter `>`, indicando que esta é uma linha da requisição; após uma linha em branco (`>` apenas), seguem uma sucessão de linhas começadas por `<`, indicando os cabeçalhos da resposta. Após uma linha em branco da resposta, indicada por um `<` vazio, começam os dados da resposta. Note a grande quantidade de cabeçalhos que é trocado em cada request/response ;)


**Requisição POST para Enviar Dados para uma API: ReqRes.in**

O ReqRes.in é outra API de teste que permite fazer requisições HTTP simuladas. Vamos usar o curl para fazer uma requisição POST e enviar dados JSON para a rota "/users" com o objetivo de criar um novo usuário.

```bash
curl -X POST -H "Content-Type: application/json" -d '{"name": "John Doe", "job": "Developer"}' https://reqres.in/api/users
```

---

## Conclusão

Este artigo fornece uma introdução à arquitetura cliente-servidor e ao protocolo HTTP, que são conhecimentos importantes para aqueles que desejam trabalhar com o desenvolvimento de Aplicações para Web.

É importante ressaltar, entretanto, que não abordamos aqui algumas questões importantes relacionadas à segurança e métodos de autenticação, mas que serão abordados eventualmente em outros artigos.