# HTTP, recursos e estado da aplicação

Pedidos e respostas, métodos, sessões, cache, origem e permissões no navegador.

Página: https://resumos.rgo.pt/cadeiras/lbaw/http-estado/

O navegador pede `GET /sessoes/12` para consultar a sessão S12. O servidor interpreta o endereço, verifica o acesso e devolve uma representação da sessão. Uma compra usa outro pedido, que altera o estado. HTTP descreve estas mensagens; a aplicação decide os dados, as permissões e a coordenação da compra.

## URL e recurso

Em `https://bilhetes.example:443/sessoes/12?idioma=pt#preco`, `https` é o esquema, `bilhetes.example` o host, `443` a porta, `/sessoes/12` o caminho, `idioma=pt` a query e `preco` o fragmento; o fragmento fica no cliente e não é enviado no alvo do pedido HTTP. A porta 443 é a porta predefinida de HTTPS e pode ser omitida, e o caminho é um identificador interpretado pela aplicação, sem precisar de corresponder a um ficheiro no disco.

## Pedido e resposta

Um exemplo textual em HTTP/1.1:

```
GET /sessoes/12 HTTP/1.1
Host: bilhetes.example
Accept: text/html
Cookie: sessao=identificador_opaco
```

A primeira linha contém método, alvo e versão. Os cabeçalhos acrescentam metadados. Após uma linha vazia pode existir um corpo. Uma resposta contém código de estado, cabeçalhos e, quando apropriado, um corpo:

```
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: private, no-store

<!doctype html><title>Sessão 12</title>
```

`Content-Type` descreve o corpo enviado. `Accept` diz quais as representações aceites pelo cliente. `Authorization` pode transportar credenciais e `Cookie` transporta os cookies que o navegador associou ao pedido. Nunca assumes que um cabeçalho enviado pelo cliente prova um papel ou uma identidade sem validação no servidor.

## Seguro e idempotente são propriedades diferentes

| Método | Semântica habitual | Seguro? | Idempotente? |
| --- | --- | --- | --- |
| GET, HEAD | Ler a representação, ou só metadados. | Sim | Sim |
| POST | Pedir processamento ou criar um recurso subordinado. | Não | Não garantido |
| PUT | Criar ou substituir o estado no endereço indicado. | Não | Sim |
| DELETE | Remover a associação do recurso ao endereço. | Não | Sim |
| PATCH | Aplicar uma alteração parcial. | Não | Não garantido |

**Seguro** significa que a semântica pedida não pretende alterar o estado. Registos de acesso são efeitos laterais possíveis de uma leitura. **Idempotente** significa que repetir o mesmo pedido tem o mesmo efeito pretendido que fazê-lo uma vez. Duas eliminações podem responder 204 e depois 404 e continuar a ser idempotentes.

`GET /apagar-conta` não se torna seguro por usar GET, pois viola a semântica do método e pode ser ativado por um link, pré-carregamento ou crawler; as alterações exigem um método adequado, autorização e proteção contra CSRF quando usam credenciais automáticas. POST e PATCH podem ser desenhados com operações idempotentes, mas o método sozinho não dá essa garantia.

## Códigos que distinguem falhas

| Código | Significado relevante |
| --- | --- |
| 200 / 201 | Sucesso; 201 indica criação e pode incluir Location. |
| 204 | Sucesso sem corpo. |
| 303 | Consultar outro endereço com GET, útil após um formulário POST. |
| 304 | A representação em cache continua válida; não transporta o corpo completo. |
| 400 / 422 | Pedido inválido; 422 pode identificar conteúdo semanticamente inválido. |
| 401 | É necessária autenticação válida, com o desafio adequado. |
| 403 | O servidor compreende o pedido mas recusa a operação. |
| 404 | Recurso não encontrado, ou existência deliberadamente não revelada. |
| 409 | Conflito com o estado atual, como uma reserva já confirmada. |
| 500 | Falha interna; o detalhe técnico fica nos registos do servidor. |

O padrão POST, redirecionamento, GET evita reenviar o formulário ao recarregar a página de confirmação, mas não resolve duplicados causados por repetição de pedidos na rede. Para uma compra, um identificador único de operação pode permitir reconhecer uma repetição e devolver o resultado já registado.

## HTTP sem estado e sessões com estado

HTTP não pressupõe memória da interação anterior. A aplicação pode acrescentar estado: o servidor guarda uma sessão e envia ao navegador um identificador opaco. Em pedidos seguintes, o cookie permite procurar essa sessão. Autenticação, carrinho e permissões continuam a ser decisões da aplicação.

*   `Secure`: o cookie só é enviado em ligações seguras adequadas.
*   `HttpOnly`: impede leitura do cookie pelas APIs de JavaScript. Não impede que um XSS execute ações com a sessão.
*   `SameSite`: limita o envio do cookie em certos contextos entre sites. É uma defesa adicional, não substitui toda a proteção contra CSRF.
*   `Path`, domínio e expiração delimitam o envio e a duração; não servem como autorização sobre recursos.

Renova o identificador da sessão ao autenticar para impedir que um identificador escolhido antes do login seja aproveitado por outra pessoa. No logout, termina a sessão no servidor e invalida as credenciais associadas.

![O navegador envia método, endereço e cookie. O servidor valida sessão e autorização, consulta a base de dados e devolve código, cabeçalhos e corpo. A sessão reside no servidor e o navegador conserva um identificador.](https://resumos.rgo.pt/cadeiras/lbaw/http-estado/figura-1.svg)

## Cache e validação

Uma resposta pública pode ser partilhada por caches se a política o permitir. Uma página pessoal exige uma política adequada para evitar exposição:

| Cache-Control | Armazenamento | Antes de reutilizar |
| --- | --- | --- |
| `no-store` | Pede que não seja armazenada | Não reutilizar uma cópia armazenada sob esta diretiva |
| `no-cache` | Permite armazenar | Exige validação com o servidor |

`ETag` identifica uma versão de representação. O cliente envia `If-None-Match` e o servidor pode responder 304 se continuar válida. A resposta reduz o corpo transmitido; não elimina o pedido nem a autorização. Um resultado em cache não deve contornar a verificação de permissões.

## Origem, CORS e HTTPS

A origem combina **esquema, host e porta**. `https://loja.example` e `http://loja.example` têm origens diferentes. A política da mesma origem limita certas leituras entre origens no navegador. CORS permite ao servidor autorizar leituras de respostas por código de determinadas origens; alguns pedidos precisam de um preflight OPTIONS.

CORS não é autenticação, não impede pedidos de clientes fora do navegador e não impede por si só CSRF. Um formulário pode enviar um pedido que altera estado mesmo quando o atacante não consegue ler a resposta. HTTPS protege o transporte, mas não corrige SQL injection, autorização em falta ou HTML inseguro.

## REST e estado da aplicação

**REST** é um estilo de arquitetura com condições próprias: separação cliente-servidor, interface uniforme, mensagens que se descrevem a si próprias, cache quando permitido e comunicação sem estado de sessão no servidor entre pedidos. Usar JSON ou nomes no plural não chega para cumprir essas condições.

O estado dos **recursos**, como os bilhetes guardados na base de dados, pode continuar no servidor. A condição sem estado diz respeito ao contexto da interação: cada pedido precisa de trazer a informação necessária para ser compreendido, sem depender de uma conversa anterior. Uma aplicação com sessão de login guardada no servidor pode usar rotas e métodos HTTP adequados sem cumprir REST estritamente. HTTP ser sem estado não impede a aplicação de guardar essa sessão; impede apenas que o protocolo a pressuponha.

## Especificar um recurso web

Antes de implementar, descreve método e caminho, permissões, parâmetros e os resultados possíveis. Por exemplo, para `GET /api/sessoes/12`:

| Parte | Contrato do exemplo |
| --- | --- |
| Pedido | `id` no caminho identifica uma sessão. |
| Acesso | Só devolve os campos públicos de uma sessão visível. |
| Sucesso | 200 e `application/json`, com `id`, `titulo` e `livres`. |
| Ausência | 404 quando não existe ou não deve ser revelada. |
| Falha técnica | 500 sem detalhes internos; o cliente mostra uma mensagem de falha. |

OpenAPI permite escrever este contrato de forma estruturada. Documentar só a página ou só os parâmetros deixa o cliente sem saber interpretar sucesso e falha. Uma resposta AJAX pode ser HTML ou JSON, consoante o contrato; o método JavaScript que lê o corpo tem de corresponder a essa escolha.

## Um diálogo completo: comprar sem duplicar

| Passo | Mensagem | Efeito |
| --- | --- | --- |
| 1 | `POST /compras` com S12 e identificador de operação K7. | O servidor autentica, autoriza e reserva capacidade com o bilhete na mesma transação. |
| 2 | `303 See Other`, `Location: /compras/1043`. | O cliente passa a consultar o resultado por GET. |
| 3 | `GET /compras/1043`, resposta 200. | Lê a compra autorizada; recarregar não compra de novo. |
| Repetição | Novo POST com o mesmo K7 e os mesmos dados. | Devolve a compra já registada, sem consumir outro lugar. |

A identificação K7 tem de ser verificada e guardada atomicamente com a compra, com unicidade no âmbito do comprador. Se dois pedidos repetidos chegarem ao mesmo tempo, verificar K7 apenas antes da transação deixa outra corrida. Se o mesmo identificador chegar com dados diferentes, recusa o conflito segundo o contrato da API.

Para a lista pública de sessões, o servidor envia `ETag`; o cliente repete com `If-None-Match` e recebe `304` sem corpo quando nada mudou. A resposta 304 não dispensa autorização nas páginas pessoais: cada pedido volta a verificar permissões antes de reutilizar cache.

## Exercícios

Efeito e código de resposta

`DELETE` responde 204 na primeira vez e 404 na segunda. Pode ser idempotente?

Pista

Compara o estado do recurso depois de um e dois pedidos.

Mais uma pista

Em ambos, o recurso pode estar removido.

Solução

Pode ser idempotente: repetir não cria um efeito adicional pretendido. O código pode descrever situações diferentes.

*   **Sim, se o efeito pretendido final for o mesmo..** Idempotência não exige respostas iguais.
*   **Não, os códigos têm de ser iguais..** A definição diz respeito ao efeito pretendido.
*   **Não, DELETE tem de ser seguro..** Seguro e idempotente são propriedades diferentes.

Erros frequentes

Não uses igualdade de resposta como definição de idempotência.

[Voltar à explicação](https://resumos.rgo.pt/cadeiras/lbaw/http-estado/#seguro-e-idempotente-s%C3%A3o-propriedades-diferentes)

O que o navegador limita

CORS substitui a autenticação de uma API?

Pista

Pensa num cliente de linha de comandos.

Mais uma pista

O servidor continua a verificar credenciais e permissões.

Solução

Não. CORS não é um controlo de identidade ou de autorização, nem proteção completa contra CSRF.

*   **Não. Controla certas leituras entre origens no navegador..** Outro cliente pode enviar pedidos e precisa de autenticação própria.
*   **Sim, só o site autorizado pode contactar o servidor..** Clientes fora do navegador não obedecem à política CORS.
*   **Sim, se todos os pedidos forem POST..** O método não prova identidade.

Erros frequentes

Não interpretes uma limitação do navegador como recusa de todos os clientes.

[Voltar à explicação](https://resumos.rgo.pt/cadeiras/lbaw/http-estado/#origem-cors-e-https)

Distinguir no-cache de no-store

Qual permite armazenar, mas exige validação antes de reutilizar?

Pista

Uma resposta pode existir em cache sem poder ser reutilizada diretamente.

Mais uma pista

O servidor pode responder 304 após validação.

Solução

no-cache permite armazenamento com validação. no-store pede que não seja armazenado.

*   **no-cache..** O nome não significa que nunca pode ser guardado.
*   **no-store..** Pede que não seja armazenado.
*   **Qualquer ETag sem política..** Um validador não define sozinho todas as regras de cache.

Erros frequentes

Não deduzas a semântica só da tradução literal do nome.

[Voltar à explicação](https://resumos.rgo.pt/cadeiras/lbaw/http-estado/#cache-e-valida%C3%A7%C3%A3o)

Escrever o diálogo POST, 303 e GET

Escreve os três passos de uma compra que sobrevive a recarregar a confirmação e a repetir o POST na rede.

Pista

Recarregar faz GET, não POST.

Mais uma pista

Um identificador de operação reconhece a repetição.

Solução

POST /compras com sessão S12 e identificador K7 cria a compra 1043 e responde 303 com Location: /compras/1043. GET nesse endereço devolve 200 com a compra autorizada. A repetição com o mesmo K7 e os mesmos dados devolve 1043, sem novo bilhete; a unicidade de K7 por comprador e o seu registo pertencem à mesma transação da compra.

Confere a tua resposta:

*   Uso POST para alterar e GET para ler.
*   Incluo 303 com Location.
*   Trato repetição com idempotência.

Erros frequentes

303 não resolve duplicados de rede sozinho.

[Voltar à explicação](https://resumos.rgo.pt/cadeiras/lbaw/http-estado/#um-di%C3%A1logo-completo-comprar-sem-duplicar)
