HTTP POST com parâmetros de consulta de URL - boa ideia ou não? [fechadas]

451

Estou projetando uma API para passar por HTTP e estou pensando se o uso do comando HTTP POST, mas apenas com parâmetros de consulta de URL e sem corpo de solicitação, é um bom caminho.

Considerações:

  • O "bom design da Web" exige que ações não idempotentes sejam enviadas via POST. Esta é uma ação não idempotente.
  • É mais fácil desenvolver e depurar este aplicativo quando os parâmetros de solicitação estão presentes no URL.
  • A API não se destina ao uso generalizado.
  • Parece que fazer uma solicitação POST sem corpo levará um pouco mais de trabalho, por exemplo, um Content-Length: 0cabeçalho deve ser explicitamente adicionado.
  • Também me parece que um POST sem corpo é um pouco contrário às expectativas da maioria dos desenvolvedores e estruturas HTTP.

Existem mais armadilhas ou vantagens em enviar parâmetros em uma solicitação POST por meio da consulta de URL em vez do corpo da solicitação?

Editar: A razão pela qual isso está sendo considerado é que as operações não são idempotentes e têm efeitos colaterais diferentes da recuperação. Veja a especificação HTTP :

Em particular, foi estabelecida a convenção de que os métodos GET e HEAD NÃO DEVEM ter o significado de tomar uma ação diferente da recuperação. Esses métodos devem ser considerados "seguros". Isso permite que os agentes do usuário representem outros métodos, como POST, PUT e DELETE, de uma maneira especial, para que o usuário fique ciente do fato de que uma ação possivelmente insegura está sendo solicitada.

...

Os métodos também podem ter a propriedade "idempotência", pois (além de problemas de erro ou expiração) os efeitos colaterais de N> 0 solicitações idênticas são os mesmos que para uma única solicitação. Os métodos GET, HEAD, PUT e DELETE compartilham essa propriedade. Além disso, os métodos OPTIONS e TRACE NÃO DEVEM ter efeitos colaterais e, portanto, são inerentemente idempotentes.

Steven Huwig
fonte
11
Por que usar o POST se você não deseja fornecer dados no corpo?
2159 Sunny Milenov
114
Porque a operação não é idempotente.
Steven Huwig 04/03/09
20
@ Jared, observe que a palavra "REST" não aparece nesta pergunta há 2,5 anos. :) A especificação HTTP sobre idempotência se aplica, independentemente da arquitetura do tipo do mês para os serviços da web. Felizmente, o sistema para o qual essa API foi projetada para proxy ficou obsoleto.
Steven Huwig 17/09/11
5
Como os logs do servidor não registram parâmetros POST, eles registram as cadeias de consulta. É muito mais fácil executar a série de solicitações sem instrumentá-la no navegador e, em seguida, observar o rastreio, do que clicar nelas. Além disso, a API não era de navegador para servidor, mas de servidor para servidor. Mais importante, todo o caso foi encerrado de qualquer maneira. :)
Steven Huwig
13
Para quem não sabe o que significa idempotente: | restapitutorial.com/lessons/idempotency.html
Christopher Grigg /

Respostas:

259

Se sua ação não for idempotente, você DEVE usar POST. Se não, você está apenas pedindo problemas na linha. GET, PUTe DELETEmétodos devem ser idempotentes. Imagine o que aconteceria no seu aplicativo se o cliente estivesse buscando previamente todas as GETsolicitações possíveis para o seu serviço - se isso causasse efeitos colaterais visíveis ao cliente, algo estaria errado.

Concordo que o envio de um POSTcom uma string de consulta, mas sem um corpo, parece estranho, mas acho que pode ser apropriado em algumas situações.

Pense na parte da consulta de uma URL como um comando para o recurso para limitar o escopo da solicitação atual. Normalmente, as strings de consulta são usadas para classificar ou filtrar uma GETsolicitação (como ?page=1&sort=title), mas suponho que faça sentido POSTtambém limitar o escopo (talvez como ?action=delete&id=5).

Don McCaughey
fonte
4
Selecionei esta resposta para este caso em particular, mas acho que o argumento de R. Bemrose é atraente para APIs públicas.
Steven Huwig 15/03/09
4
Não acho que a resposta dele seja estritamente correta. Se você conhece os parâmetros de URL para o seu formulário quando a página HTML é enviada para o cliente, você pode anexar esses parâmetros ao atributo de ação do formulário; caso contrário, o JavaScript pode definir os parâmetros de URL quando o formulário é enviado.
22411 Don McCaughey
3
que tal uma postagem de um arquivo xml em um URL com parâmetros de consulta? isso é possível?
OpenCoderX 02/02
3
Outro exemplo: os dados da solicitação podem estar na entidade http, enquanto o formato solicitado da resposta é passado no parâmetro de consulta ( /action?response_format=json)
rds
4
O +1 aprendeu algo hoje. Excluir tem um detalhe técnico para ser idempotente. Se o objeto for realmente excluído, você receberá um 404 não encontrado; portanto, o servidor terá o mesmo estado, mas a resposta será diferente. Veja a imagem da vaca: restapitutorial.com/lessons/idempotency.html
JPK
131

Todo mundo está certo: fique com o POST para solicitações não idempotentes.

Que tal usar uma sequência de consulta URI e solicitar conteúdo? Bem, é HTTP válido (veja a nota 1), então por que não ?!

Também é perfeitamente lógico: os URLs, incluindo sua parte da cadeia de caracteres de consulta, destinam-se à localização de recursos. Enquanto os verbos do método HTTP (POST - e seu conteúdo opcional de solicitação) são para especificar ações ou o que fazer com os recursos. Essas devem ser preocupações ortogonais. (Mas não são preocupações ortogonais maravilhosas para o caso especial de ContentType = application / x-www-form-urlencoded, consulte a nota 2 abaixo.)

Nota 1: A especificação HTTP (1.1) não declara que os parâmetros e o conteúdo da consulta são mutuamente exclusivos para um servidor HTTP que aceita solicitações POST ou PUT. Portanto, qualquer servidor é livre para aceitar os dois. Ou seja, se você escrever o servidor, não há nada que o impeça de optar por aceitar os dois (exceto talvez uma estrutura inflexível). Geralmente, o servidor pode interpretar as cadeias de consulta de acordo com as regras que desejar. Ele pode até interpretá-los com lógica condicional que também se refere a outros cabeçalhos como o Tipo de conteúdo, o que leva à Nota 2:

Nota 2: Se um navegador web é a principal forma as pessoas estão acessando o aplicativo web, e application / x-www-form-urlencoded é o tipo de conteúdo que eles estão postando, em seguida, você deve seguir as regras para que Content-Type. E as regras para o código application / x-www-form-url são muito mais específicas (e francamente, incomuns): nesse caso, você deve interpretar o URI como um conjunto de parâmetros, e não como um local de recurso. [Este é o mesmo ponto de utilidade que Powerlord levantou; pode ser difícil usar formulários da web para postar conteúdo no seu servidor. Apenas expliquei um pouco diferente.]

Nota 3: para que servem originalmente as strings de consulta? O RFC 3986 define cadeias de consulta HTTP como uma parte do URI que funciona como uma maneira não hierárquica de localizar um recurso.

Caso os leitores que fazem essa pergunta desejem perguntar o que é uma boa arquitetura RESTful: o padrão da arquitetura RESTful não exige que os esquemas de URI funcionem de uma maneira específica. A arquitetura RESTful se preocupa com outras propriedades do sistema, como armazenamento em cache de recursos, o design dos próprios recursos (comportamento, recursos e representações) e se a idempotência é satisfeita. Ou, em outras palavras, obter um design altamente compatível com o protocolo HTTP e seu conjunto de verbos de método HTTP. :-) (Em outras palavras, a arquitetura RESTful não é muito positiva com a localização dos recursos .)

Nota final: às vezes, os parâmetros de consulta são usados ​​para outras coisas, que não estão localizando recursos nem codificando conteúdo. Já viu um parâmetro de consulta como 'PUT = true' ou 'POST = true'? Essas são soluções alternativas para navegadores que não permitem o uso dos métodos PUT e POST. Embora esses parâmetros sejam vistos como parte da cadeia de consulta da URL (na conexão), eu argumento que eles não fazem parte da consulta da URL em espírito .

Tim Lovell-Smith
fonte
66

Você quer razões? Aqui está um:

Um formulário da web não pode ser usado para enviar uma solicitação para uma página que usa uma combinação de GET e POST. Se você definir o método do formulário como GET, todos os parâmetros estarão na string de consulta. Se você definir o método do formulário como POST, todos os parâmetros estarão no corpo da solicitação.

Fonte: Padrão HTML 4.01, seção 17.13 Submissão de formulários

Powerlord
fonte
10
Esse é um argumento decente, mas acho que as implementações de Javascript do navegador moderno meio que o tornam um ponto discutível. Eu vou pensar sobre isso - é atraente de uma maneira à prova de futuro. Só porque não estou usando um formulário para isso agora não significa que não vou querer mais tarde.
Steven Huwig 04/03/09
9
Misturar GET com POST é apenas uma péssima idéia - quebrar terrivelmente o HTTP e sem uma boa razão.
aehlke
6
Esse trecho não aparece na página que você vinculou
Gareth
40
Certo, mas o atributo method apenas define como o "conjunto de dados do formulário" é incluído na solicitação. Quando o methodPOST é, não há menção de alterar o URI no formulário action. E é claro que qualquer URI já pode conter uma parte da string de consulta.
Gareth
16
@ Powerlord Isso está errado. Tente configurar um formulário para POST com uma ação de por exemplo. /Books?bookCode=1234. O servidor da Web obterá vars de formulário POST e uma string de consulta.
Jez
9

Do ponto de vista programático, para o cliente está empacotando parâmetros e anexando-os ao URL e conduzindo um POST versus um GET. No lado do servidor, está avaliando os parâmetros de entrada da string de consulta em vez dos bytes postados. Basicamente, é uma lavagem.

Onde pode haver vantagens / desvantagens em como plataformas específicas de clientes funcionam com as rotinas POST e GET em sua pilha de rede, bem como em como o servidor da Web lida com essas solicitações. Dependendo da sua implementação, uma abordagem pode ser mais eficiente que a outra. Saber que guiaria sua decisão aqui.

No entanto, da perspectiva de um programador, prefiro permitir um POST com todos os parâmetros no corpo ou um GET com todos os parâmetros no URL e ignorar explicitamente os parâmetros de URL com qualquer solicitação POST. Evita confusão.

jro
fonte
8

Eu acho que ainda pode ser bastante RESTful ter argumentos de consulta que identifiquem o recurso na URL, mantendo a carga útil do conteúdo confinada ao corpo do POST. Isso parece separar as considerações de "O que estou enviando?" versus "Para quem estou enviando?".

swizzcheez
fonte
5
A pergunta não era sobre REST.
Steven Huwig
3
@ user359996 Nem todas as APIs HTTP são RESTful. De fato, a maioria das APIs que afirmam que realmente não são. Além disso, o fato é que o REST também não é apenas HTTP.
Alec Mev
4

O campo REST possui alguns princípios orientadores que podemos usar para padronizar a maneira como usamos verbos HTTP. Isso é útil ao criar APIs RESTful como você está fazendo.

Em poucas palavras: GET deve ser somente leitura, ou seja, não afeta o estado do servidor. POST é usado para criar um recurso no servidor. PUT é usado para atualizar ou criar um recurso. DELETE é usado para excluir um recurso.

Em outras palavras, se sua ação da API alterar o estado do servidor, o REST nos aconselha a usar POST / PUT / DELETE, mas não GET.

Os agentes de usuários geralmente entendem que fazer vários POSTs é ruim e alertam contra isso, porque a intenção do POST é alterar o estado do servidor (por exemplo, pagar por mercadorias no check-out) e você provavelmente não deseja fazer isso duas vezes!

Compare com um GET que você pode fazer quantas vezes quiser (idempotente).

veleiro
fonte
13
O campo REST diz que você deve usar o HTTP conforme definido na especificação do HTTP. RFC2616 Nada mais, nada menos.
Darrel Miller
1
@Darrel Referindo-se a ibm.com/developerworks/webservices/library/ws-restful : O REST solicita que os desenvolvedores usem métodos HTTP explicitamente e de maneira consistente com a definição do protocolo. Esse princípio básico de design do REST estabelece um mapeamento individual entre operações de criação, leitura, atualização e exclusão (CRUD) e métodos HTTP. De acordo com este mapeamento: Para criar um recurso no servidor, use POST. Para recuperar um recurso, use GET. Para alterar o estado de um recurso ou atualizá-lo, use PUT. Para remover ou excluir um recurso, use DELETE.
saille
5
Desculpe, mas isso está errado. O REST requer conformidade com uma interface uniforme. Se você estiver usando HTTP, essa interface uniforme será definida em parte pelo RFC 2616. Nessa especificação, não há um mapeamento individual entre criar, ler, atualizar e excluir e os métodos HTTP.
Darrel Miller
3
GET e DELETE mapeiam muito bem para Ler e Excluir em CRUD, mas usar PUT / POST para Atualização e Criação não é tão simples. Veja stackoverflow.com/questions/630453/put-vs-post-in-rest
dcstraw
5
Olhando para isso 6 anos depois, e considerando que a pergunta foi vista ~ 100k vezes, acho que vale a pena fazer uma pequena atualização. Darrel está correto de acordo com a definição de Fielding de REST ( ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm ) - não há menção ao mapeamento de verbos HTTP para CRUD. O conselho do desenvolvedor da IBM (link no comentário acima) reflete a prática comum na implementação de APIs RESTful, não a definição de REST de Fielding.
Saille # 22/15
-13

Concordo - provavelmente é mais seguro usar uma solicitação GET se você estiver apenas transmitindo dados no URL e não no corpo. Veja esta pergunta semelhante para algumas visualizações adicionais sobre todo o conceito POST + GET.

Marc Novakowski
fonte
17
Se a operação tiver efeitos colaterais, certamente não é 'seguro' usar o método GET porque o navegador assume que todos os GETs são idempotentes.
dcstraw
Os mecanismos de pesquisa também convertem isso em um pesadelo, pois o Google "clica" com segurança em todos os links com a solicitação GET, mas omite todo o resto. Não é tão seguro sair de um serviço que um rastreador inocente pode acidentalmente limpar o banco de dados.
Alejandro