HTTP, recursos e estado da aplicação
Pedidos e respostas, métodos, sessões, cache, origem e permissões no navegador.
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.
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.
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.
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.
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.