Estou desenvolvendo um novo serviço web RESTful para nosso aplicativo.
Ao fazer um GET em determinadas entidades, os clientes podem solicitar o conteúdo da entidade. Se eles quiserem adicionar alguns parâmetros (por exemplo, classificar uma lista), eles podem adicionar esses parâmetros na string de consulta.
Como alternativa, quero que as pessoas possam especificar esses parâmetros no corpo da solicitação. O HTTP / 1.1 não parece explicitamente proibir isso. Isso permitirá que eles especifiquem mais informações e facilite a especificação de solicitações XML complexas.
Minhas perguntas:
- Esta é uma boa ideia?
- Os clientes HTTP terão problemas com o uso de corpos de solicitação em uma solicitação GET?
Respostas:
O comentário de Roy Fielding sobre a inclusão de um corpo com uma solicitação GET .
Sim, você pode enviar um corpo de solicitação com GET, mas ele não deve ter nenhum significado. Se você der um significado analisando-o no servidor e alterando sua resposta com base em seu conteúdo , estará ignorando esta recomendação na especificação HTTP / 1.1, seção 4.3 :
E a descrição do método GET na especificação HTTP / 1.1, seção 9.3 :
que afirma que o corpo da solicitação não faz parte da identificação do recurso em uma solicitação GET, apenas o URI da solicitação.
Atualização O RFC2616 referido como "HTTP / 1.1 spec" agora está obsoleto. Em 2014, foi substituído pelos RFCs 7230-7237. A citação "o corpo da mensagem DEVE ser ignorada ao manipular a solicitação" foi excluída. Agora é apenas "O enquadramento da mensagem de solicitação é independente da semântica do método, mesmo que o método não defina nenhum uso para o corpo da mensagem" A segunda cotação "O método GET significa recuperar qualquer informação ... identificada pelo Request-URI" Foi apagado. - De um comentário
fonte
Embora você possa fazer isso, na medida em que não seja explicitamente impedido pela especificação HTTP, sugiro evitá-lo simplesmente porque as pessoas não esperam que as coisas funcionem dessa maneira. Existem muitas fases em uma cadeia de solicitações HTTP e, embora elas "estejam em sua maioria" em conformidade com as especificações HTTP, você só tem certeza de que elas se comportarão como tradicionalmente usadas pelos navegadores da Web. (Estou pensando em coisas como proxies transparentes, aceleradores, kits de ferramentas A / V etc.)
Esse é o espírito por trás do Princípio da Robustez, aproximadamente "seja liberal no que você aceita e conservador no que você envia"; você não deseja forçar os limites de uma especificação sem uma boa razão.
No entanto, se você tiver um bom motivo, siga em frente.
fonte
Você provavelmente encontrará problemas se tentar tirar proveito do cache. Os proxies não vão procurar no corpo GET para ver se os parâmetros têm impacto na resposta.
fonte
Nem o restclient nem o console REST suportam isso, mas o curl sim.
A especificação HTTP diz na seção 4.3
A seção 5.1.1 nos redireciona para a seção 9.x para os vários métodos. Nenhum deles proíbe explicitamente a inclusão de um corpo da mensagem. Contudo...
A seção 5.2 diz
e a Seção 9.3 diz
Que juntos sugerem que, ao processar uma solicitação GET, um servidor não precisa examinar nada além do campo de cabeçalho Request-URI e Host.
Em resumo, a especificação HTTP não impede que você envie um corpo da mensagem com GET, mas há ambiguidade suficiente que não me surpreenderia se não fosse suportado por todos os servidores.
fonte
GET /contacts/100/addresses
retorna uma coleção de endereços para a pessoa comid=100
.O Elasticsearch aceita solicitações GET com um corpo. Parece até que esse é o caminho preferido: guia do Elasticsearch
Algumas bibliotecas clientes (como o driver Ruby) podem registrar o comando cry no stdout no modo de desenvolvimento e ele está usando essa sintaxe extensivamente.
fonte
curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }'
é equivalente a incluir a carga útil comosource
param: #curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
O que você está tentando alcançar é feito há muito tempo com um método muito mais comum e que não depende do uso de uma carga útil com o GET.
Você pode simplesmente criar seu tipo de mídia de pesquisa específico ou, se quiser ser mais RESTful, usar algo como OpenSearch e enviar a solicitação ao URI que o servidor instruiu, digamos / search. O servidor pode gerar o resultado da pesquisa ou criar o URI final e redirecionar usando um 303.
Isso tem a vantagem de seguir o método PRG tradicional, ajuda o cache de intermediários a armazenar em cache os resultados, etc.
Dito isso, os URIs são codificados de qualquer maneira para qualquer coisa que não seja ASCII, assim como application / x-www-form-urlencoded e multipart / form-data. Eu recomendaria usar isso em vez de criar outro formato json personalizado, se sua intenção é oferecer suporte a cenários ReSTful.
fonte
Você pode enviar um GET com um corpo ou enviar um POST e desistir da religiosidade RESTish (não é tão ruim, cinco anos atrás, havia apenas um membro dessa fé - seus comentários acima).
Tampouco são ótimas decisões, mas o envio de um corpo GET pode evitar problemas para alguns clientes - e alguns servidores.
Fazer um POST pode ter obstáculos em algumas estruturas RESTish.
Julian Reschke sugeriu acima o uso de um cabeçalho HTTP não padrão como "SEARCH", que poderia ser uma solução elegante, exceto que é ainda menos provável que seja suportado.
Pode ser mais produtivo listar clientes que podem e não podem executar cada uma das opções acima.
Clientes que não podem enviar um GET com body (que eu saiba):
Clientes que podem enviar um GET com o corpo:
Servidores e bibliotecas que podem recuperar um corpo do GET:
Servidores (e proxies) que retiram um corpo de GET:
fonte
SEARCH
método poderia quebrar ao longo do caminho? Se proxies não entendem um método, eles são esperados para passá-lo através como é, então eu não estou muito certo por que você acha que ele iria quebrar nada ...Eu coloquei essa pergunta no IETF HTTP WG. O comentário de Roy Fielding (autor do documento http / 1.1 em 1998) foi que
O RFC 7213 (HTTPbis) afirma:
Parece claro agora que a intenção era proibir o significado semântico nos corpos de solicitação GET, o que significa que o corpo da solicitação não pode ser usado para afetar o resultado.
Existem proxies por aí que definitivamente interromperão sua solicitação de várias maneiras se você incluir um corpo no GET.
Então, em resumo, não faça isso.
fonte
O Google, por exemplo, está fazendo pior do que ignorá-lo, ele o considerará um erro !
Tente você mesmo com um simples netcat:
(o conteúdo 1234 é seguido pelo CR-LF, totalizando 6 bytes)
e você receberá:
Você também recebe 400 solicitações incorretas do Bing, Apple, etc ..., que são atendidas pelo AkamaiGhost.
Portanto, eu não recomendaria o uso de solicitações GET com uma entidade do corpo.
fonte
GET
solicitações, é porque seu próprio servidor personalizado é capaz de lidar com isso. A questão, portanto, é se as outras "partes móveis" (navegadores, caches, etc.) funcionarão corretamente.GET
determinado terminal - não tem nada a ver com o usoGET
no caso geral. Uma carga aleatória poderia interromper aPOST
mesma facilidade e retornar o mesmo400 Bad Request
, se o conteúdo não estivesse em um formato que fizesse sentido no contexto da solicitação específica.Do RFC 2616, seção 4.3 , "Corpo da mensagem":
Ou seja, os servidores sempre devem ler qualquer corpo de solicitação fornecido da rede (verifique Comprimento do conteúdo ou leia um corpo em partes, etc.). Além disso, os proxies devem encaminhar qualquer organismo de solicitação que receberem. Então, se o RFC definir semântica para o corpo para o método especificado, o servidor poderá realmente usar o corpo da solicitação para gerar uma resposta. No entanto, se o RFC não definir semântica para o corpo, o servidor deverá ignorá-lo.
Isso está de acordo com a citação de Fielding acima.
A Seção 9.3 , "GET", descreve a semântica do método GET e não menciona os corpos de solicitação. Portanto, um servidor deve ignorar qualquer corpo de solicitação recebido em uma solicitação GET.
fonte
De acordo com XMLHttpRequest, não é válido. Do padrão :
No entanto, acho que não, porque a solicitação GET pode precisar de grande conteúdo corporal.
Portanto, se você confiar no XMLHttpRequest de um navegador, provavelmente não funcionará.
fonte
Se você realmente deseja enviar o corpo JSON / XML capturável para o aplicativo Web, o único local razoável para colocar seus dados é a string de consulta codificada com RFC4648: Codificação Base 64 com URL e Alfabeto Seguro de Nome de Arquivo . Claro que você pode apenas urlencode JSON e colocar no valor do parâmetro da URL, mas Base64 fornece um resultado menor. Lembre-se de que existem restrições de tamanho de URL, consulte Qual é o tamanho máximo de um URL em diferentes navegadores? .
Você pode pensar que o
=
caractere de preenchimento do Base64 pode ser ruim para o valor de parâmetro da URL, mas parece que não - veja esta discussão: http://mail.python.org/pipermail/python-bugs-list/2007-February/037195.html . No entanto, você não deve colocar dados codificados sem o nome do parâmetro, pois a string codificada com preenchimento será interpretada como chave param com valor vazio. Eu usaria algo como?_b64=<encodeddata>
.fonte
Vary
cabeçalho, eu não estava ciente de seu potencial real.Eu não recomendaria isso, isso é contrário às práticas padrão e não oferece muito em troca. Você deseja manter o corpo para o conteúdo, não para opções.
fonte
E os cabeçalhos codificados em base64 não conformes? "ALGUNS PARQUES DE APLICATIVOS: sdfSD45fdg45 / aS"
Restrições de comprimento hm. Você não consegue fazer a sua manipulação no POST distinguir entre os significados? Se você deseja parâmetros simples como classificação, não vejo por que isso seria um problema. Eu acho que é certeza que você está preocupado.
fonte
x-
prefixo; quaisquer limites no comprimento dos cabeçalhos seriam inteiramente um limite arbitrário do servidor.Estou chateado que REST como protocolo não suporta OOP e
Get
método é prova. Como solução, você pode serializar seu DTO para JSON e criar uma sequência de consultas. No lado do servidor, você poderá desserializar a string de consulta para o DTO.Dê uma olhada em:
A abordagem baseada em mensagens pode ajudá-lo a resolver a restrição do método Get. Você poderá enviar qualquer DTO como no corpo da solicitação
A estrutura de serviço da web Nelibur fornece funcionalidade que você pode usar
fonte
Por exemplo, ele funciona com Curl, Apache e PHP.
Arquivo PHP:
Comando do console:
Resultado:
fonte
$_POST
quando o corpo for enviado com uma solicitação POST eapplication/x-www-form-urlencoded
. Isso significa que o corpo é ignorado em umaGET
solicitação. Neste caso:$_GET
e$_POST
são muito enganadores de qualquer maneira neste momento. Então uso melhor #php://input
IMHO, você pode simplesmente enviar o
JSON
codificado (ou seja,encodeURIComponent
) daURL
maneira que você não violar asHTTP
especificações e leváJSON
-lo ao servidor.fonte
Você tem uma lista de opções muito melhores do que usar um corpo de solicitação com GET.
Vamos supor que você tenha categorias e itens para cada categoria. Ambos devem ser identificados por um ID ("catid" / "itemid" para fins deste exemplo). Você deseja classificar de acordo com outro parâmetro "sortby" em uma "ordem" específica. Você deseja passar parâmetros para "sortby" e "order":
Você pode:
example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
example.com/category/{catid}/item/{itemid}/{sortby}/{order}
Todos têm suas desvantagens, mas são muito melhores do que usar um GET com um corpo.
fonte
Mesmo que uma ferramenta popular use isso, como citado com freqüência nesta página, acho que ainda é uma péssima idéia, sendo muito exótica, apesar de não ser proibida pelas especificações.
Muitas infraestruturas intermediárias podem simplesmente rejeitar tais solicitações.
Por exemplo, esquecer de usar algum do CDN disponível na frente do seu web site, como este um :
E sim, suas bibliotecas cliente também podem não suportar a emissão de tais solicitações, conforme relatado neste comentário .
fonte
Estou usando o RestTemplate da estrutura Spring no meu programa cliente e, no lado do servidor, defini uma solicitação GET com um corpo Json. Meu objetivo principal é o mesmo que o seu: quando a solicitação possui vários parâmetros, colocá-los no corpo parece mais organizado do que colocá-los na cadeia URI prolongada. Sim?
Mas, infelizmente, não está funcionando! O lado do servidor lançou a seguinte exceção:
org.springframework.http.converter.HttpMessageNotReadableException: o corpo da solicitação necessária está ausente ...
Mas tenho certeza de que o corpo da mensagem é fornecido corretamente pelo código do meu cliente, então o que há de errado?
Eu rastreei o método RestTemplate.exchange () e encontrei o seguinte:
Observe que no método executeInternal (), o argumento de entrada 'bufferedOutput' contém o corpo da mensagem fornecido pelo meu código. Eu vi através do depurador.
No entanto, devido ao prepareConnection (), o getDoOutput () em executeInternal () sempre retorna false, o que, por sua vez, torna o bufferedOutput completamente ignorado! Não é copiado no fluxo de saída.
Consequentemente, meu programa de servidor não recebeu nenhum corpo de mensagem e lançou essa exceção.
Este é um exemplo sobre o RestTemplate da estrutura Spring. O ponto é que, mesmo que o corpo da mensagem não seja mais proibido pela especificação HTTP, algumas bibliotecas ou estruturas de clientes ou servidores ainda podem estar em conformidade com a especificação antiga e rejeitar o corpo da mensagem da solicitação GET.
fonte