HTTP GET com corpo da solicitação

2110

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?

http://tools.ietf.org/html/rfc2616

Evert
fonte
552
A vantagem é que permite enviar facilmente corpos de solicitação XML ou JSON, não possui restrição de comprimento e é mais fácil de codificar (UTF-8).
Evert
29
Se você procura um método seguro e idempotente que permita corpos de solicitação, consulte SEARCH, PROPFIND e REPORT. É claro que não usar GET e ter um corpo de solicitação derrota o cache mais ou menos.
Julian Reschke
226
@fijiaaron: São 3 anos depois e, desde então, tenho uma vasta experiência escrevendo serviços web. É basicamente tudo o que tenho feito nos últimos anos. Posso dizer com segurança que é realmente uma péssima idéia adicionar um corpo a uma solicitação GET. As duas principais respostas permanecem como uma pedra.
Evert
26
@ Ellesedil: Simplificando: Quaisquer vantagens que existem ao usar GET sobre POST, existem por causa de como o HTTP é projetado. Essas vantagens não existem mais quando você viola o padrão dessa maneira. Portanto, resta apenas um motivo para usar GET + um corpo de solicitação em vez de POST: Estética. Não sacrifique o design robusto sobre a estética.
Evert
7
Para sublinhar o que Evert disse: "não há restrição de comprimento". Se o seu GET com parâmetros de consulta está quebrando a restrição de comprimento (de 2048), que outra opção existe além de colocar as informações da string de consulta em um objeto json, por exemplo, no corpo da solicitação.
Kieran Ryan

Respostas:

1725

O comentário de Roy Fielding sobre a inclusão de um corpo com uma solicitação GET .

Sim. Em outras palavras, qualquer mensagem de solicitação HTTP pode conter um corpo de mensagem e, portanto, deve analisar as mensagens com isso em mente. A semântica do servidor para GET, no entanto, é restrita para que um corpo, se houver, não tenha significado semântico para a solicitação. Os requisitos de análise são separados dos requisitos de semântica de métodos.

Portanto, sim, você pode enviar um corpo com GET, e não, nunca é útil fazê-lo.

Isso faz parte do design em camadas do HTTP / 1.1 que ficará claro novamente quando a especificação for particionada (trabalho em andamento).

.... Roy

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 :

[...] se o método de solicitação não incluir semântica definida para um corpo de entidade, o corpo da mensagem DEVE ser ignorado ao lidar com o pedido.

E a descrição do método GET na especificação HTTP / 1.1, seção 9.3 :

O método GET significa recuperar qualquer informação [...] identificada pelo Request-URI.

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

Paul Morgan
fonte
71
Cache / proxy são as duas coisas que você provavelmente quebrará, sim. "Semântica" é apenas outra maneira de dizer "a maneira como as pessoas que fabricam outros componentes esperam que outros componentes funcionem". Se você violar a semântica, é mais provável que você veja coisas acontecerem em lugares onde as pessoas escreveram coisas que esperavam que você honrasse essa semântica.
Stuart P. Bentley
108
O Elasticsearch é um produto bastante importante que utiliza corpos de solicitação HTTP no GET. De acordo com o manual, se uma solicitação HTTP deve suportar ter um corpo ou não é indefinida. Pessoalmente, não estou confortável em preencher um corpo de solicitação GET, mas eles parecem ter uma opinião diferente e precisam saber o que estão fazendo. elastic.co/guide/en/elasticsearch/guide/current/…
GordonM
25
@iwein, dando sentido aos corpos de solicitação GET, na verdade não é uma violação das especificações. HTTP / 1.1 especifica que os servidores devem ignorar o corpo, mas o RFC 2119 especifica que os implementadores têm permissão para ignorar as cláusulas "DEVE" se tiverem um bom motivo para fazê-lo. Em vez disso, um cliente faz violar a especificação se assume que a mudança do corpo GET irá não alterar a resposta.
Emil Lundberg
107
O RFC2616 mencionado 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 excluído . Então, sugiro editar a resposta @Jarl
Artem Nakonechny
28
Eu sei que é um fio antigo - eu tropecei nele. @Artem Nakonechny está tecnicamente certo, mas a nova especificação diz "Uma carga útil dentro de uma mensagem de solicitação GET não possui semântica definida; o envio de um corpo de carga útil em uma solicitação GET pode fazer com que algumas implementações existentes rejeitem a solicitação". Portanto, ainda não é uma boa ideia se pode ser evitado.
fastcatch
289

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.

caskey
fonte
228
O princípio da robustez é falho. Se você for liberal no que aceita, receberá uma porcaria, se tiver algum sucesso em termos de adoção, apenas porque aceita porcaria. Isso tornará mais difícil a evolução da sua interface. Basta olhar para HTML. Esse é o princípio da reeducação em ação.
Eugene Beresovsky em 9/08/11
27
Penso que o sucesso e a amplitude da adoção (e abuso) dos protocolos falam do valor do princípio da robustez.
Caskey
39
Você já tentou analisar HTML real? Não é viável implementá-lo, é por isso que quase todos - incluindo os grandes players como Google (Chrome) e Apple (Safari), não o fizeram, mas confiaram nas implementações existentes (no final, todas elas confiaram no KHTML do KDE). Essa reutilização é obviamente boa, mas você já tentou exibir html em um aplicativo .net? É um pesadelo, pois você precisa incorporar um componente - não gerenciado - IE (ou similar), com seus problemas e falhas, ou usar o componente gerenciado disponível (no codeplex) que nem permite a seleção de texto.
Eugene Beresovsky
6
A especificação HTTP não apenas permite dados do corpo com solicitação GET, mas também é uma prática comum: A popular API _search do mecanismo ElasticSearch recomenda solicitações GET com a consulta anexada em um corpo JSON. Como uma concessão para implementações incompletas de clientes HTTP, também permite solicitações POST aqui.
Christian Pietsch
3
@ChristianPietsch, é prática comum hoje. Quatro anos atrás, não era. Embora a especificação permita explicitamente que um cliente inclua opcionalmente (MAIO) uma entidade em uma solicitação (seção 7), o significado de MAIO é definido no RFC2119 e um servidor proxy (péssimo) pode ser compatível com as especificações ao mesmo tempo que retira entidades de solicitações GET, especificamente, desde que não trate, ele pode fornecer 'funcionalidade reduzida' encaminhando os cabeçalhos da solicitação e não a entidade incluída. Da mesma forma, há uma série de regras sobre quais alterações de versão DEVEM / PODEM / DEVEM ser feitas ao proxies entre diferentes níveis de protocolo.
Caskey
151

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.

Darrel Miller
fonte
10
O uso dos campos de cabeçalho ETag / Last-Modified ajuda desta maneira: quando um "GET condicional" é usado, os proxies / caches podem agir com base nessas informações.
precisa saber é o seguinte
2
Os caches do @jldupont usam a presença de validadores para saber se uma resposta obsoleta pode ser re-validada; no entanto, eles não são usados ​​como parte da chave de cache principal ou secundária.
Darrel Miller
Você pode corrigir isso com uma soma de verificação do corpo em um parâmetro de consulta
Adrian
73

Nem o restclient nem o console REST suportam isso, mas o curl sim.

A especificação HTTP diz na seção 4.3

Um corpo da mensagem NÃO DEVE ser incluído em uma solicitação se a especificação do método da solicitação (seção 5.1.1) não permitir o envio de uma entidade na solicitação.

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

O recurso exato identificado por uma solicitação da Internet é determinado examinando o campo Request-URI e Host.

e a Seção 9.3 diz

O método GET significa recuperar qualquer informação (na forma de uma entidade) identificada pelo Request-URI.

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.

Dave Durbin
fonte
2
A pata também tem a opção de suportar solicitações GET com corpos, mas deve ser ativada nas configurações.
precisa saber é o seguinte
"O método GET significa recuperar qualquer informação (na forma de uma entidade) identificada pelo Request-URI." Então, é tecnicamente ilegal / errado ter um ponto de extremidade GET que obtenha todas as entidades? Por exemplo, GET /contacts/100/addressesretorna uma coleção de endereços para a pessoa com id=100.
21420 Josh M.Jul
A biblioteca Java com segurança para testar APIs REST não suporta solicitação GET com um corpo. O Apache HttpClient também não é compatível.
Paulo Merson
Django também suporta a análise de um corpo GET
de Bruno Dedo
60

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.

jlecour
fonte
5
Estava se perguntando por que o Elasticsearch permite isso. Isso significa que esta consulta para contar todos os documentos com carga útil para uma solicitação GET curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }' é equivalente a incluir a carga útil como sourceparam: # curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
arun
40
Consultas complexas podem atingir o comprimento máximo do cabeçalho http.
precisa saber é o seguinte
11
Ele estava lendo a documentação ElasticSearch que me levou a esta pergunta como eu pensei que foi considerado uma má prática para incluir um corpo
PatrickWalker
1
Nem precisa ser uma consulta complexa. Mesmo uma rolagem simples pode retornar um scroll_id muito longo (em um cluster com muitos shards), o que levará a ultrapassar o comprimento máximo da URL, se adicionado a ela.
Brent Hronik
11
O Elasticsearch suporta a mesma solicitação usando o POST. Eles escolheram apenas permitir um corpo em um GET porque consideravam que um GET é mais semanticamente correto do que um POST quando se trata de consultar dados. É engraçado que o Elasticsearch seja mencionado muito neste tópico. Eu não usaria um exemplo (embora de um produto popular) como uma razão para seguir a prática.
DSO
33

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.

SerialSeb
fonte
4
Você pode simplesmente criar seu tipo de mídia de pesquisa específico .
Piotr Dobrogost 28/09/11
2
Por isso, eu estava dizendo que você poderia criar um tipo de mídia chamado application / vnd.myCompany.search + json que conteria o tipo de modelo de pesquisa que você deseja que um cliente emita, e o cliente poderá enviá-lo como um POST. Como destaquei, já existe um tipo de mídia para isso e é chamado OpenSearch, a reutilização de um tipo de mídia existente deve ser escolhida sobre a rota personalizada quando você pode implementar seu cenário com os padrões existentes.
precisa
14
Isso é inteligente, mas excessivamente complexo e ineficiente. Agora você deve enviar um POST com seus critérios de pesquisa, obter um URI como resposta de volta do seu POST e enviar um GET com o URI dos critérios de pesquisa ao servidor para que ele obtenha os critérios e envie o resultado de volta para você. (Exceto que a inclusão de um URI em um URI é tecnicamente impossível porque você não pode enviar algo que pode ter até 255 caracteres em algo que não pode ter mais que 255 caracteres - portanto, você deve usar um identificador parcial e seu servidor. precisa saber como resolver o URI para os seus critérios de pesquisa publicada).
fijiaaron
30

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):

  • XmlHTTPRequest Fiddler

Clientes que podem enviar um GET com o corpo:

  • maioria dos navegadores

Servidores e bibliotecas que podem recuperar um corpo do GET:

  • Apache
  • PHP

Servidores (e proxies) que retiram um corpo de GET:

  • ?
fijiaaron
fonte
2
Squid 3.1.6 também retira corpos começa quando Content-Length é 0 ou não definido, e caso contrário, envia de volta um HTTP 411 Comprimento exigido mesmo que o comprimento está definido
rkok
2
Violinista vai, mas ele avisa.
toddmo
Você está dizendo que um SEARCHmé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 ...
Alexis Wilke
22

Eu coloquei essa pergunta no IETF HTTP WG. O comentário de Roy Fielding (autor do documento http / 1.1 em 1998) foi que

"... uma implementação seria interrompida para fazer outra coisa senão analisar e descartar esse organismo se recebida"

O RFC 7213 (HTTPbis) afirma:

"Uma carga útil dentro de uma mensagem de solicitação GET não possui semântica definida;"

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.

Adrien
fonte
21

Qual servidor irá ignorá-lo? # Fijiaaron ago 30 '12 às 21:27

O Google, por exemplo, está fazendo pior do que ignorá-lo, ele o considerará um erro !

Tente você mesmo com um simples netcat:

$ netcat www.google.com 80
GET / HTTP/1.1
Host: www.google.com
Content-length: 6

1234

(o conteúdo 1234 é seguido pelo CR-LF, totalizando 6 bytes)

e você receberá:

HTTP/1.1 400 Bad Request
Server: GFE/2.0
(....)
Error 400 (Bad Request)
400. That’s an error.
Your client has issued a malformed or illegal request. That’s all we know.

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.

user941239
fonte
65
Este exemplo é inútil, porque geralmente quando as pessoas adicionam corpo às GETsolicitaçõ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.
Pacerier
6
Este é um pedido ruim, porque sua carga útil não é esperada (ou sensata) para um GET determinado terminal - não tem nada a ver com o uso GETno caso geral. Uma carga aleatória poderia interromper a POSTmesma facilidade e retornar o mesmo 400 Bad Request, se o conteúdo não estivesse em um formato que fizesse sentido no contexto da solicitação específica.
Nobar
E não apenas nesse ponto de extremidade como um todo, mas nesse URL específico .
Lawrence Dol
1
Isso é irrelevante, porque é apenas a implementação do servidor do Google nesse URL. Por isso, não faz sentido para a questão
Joel Duckworth
para mim, foi útil, pois eu estava tentando usar as funções do firebase com uma solicitação get + body, e esse erro pode ser muito enigmático e difícil de entender.
Scrimau
19

Do RFC 2616, seção 4.3 , "Corpo da mensagem":

Um servidor deve ler e encaminhar um corpo da mensagem em qualquer solicitação; se o método de solicitação não inclui semântica definida para um corpo de entidade, o corpo da mensagem DEVE ser ignorado ao manipular o pedido.

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.

izrik
fonte
A Seção 9.5 , "POST", também não menciona os organismos de solicitação, portanto, essa lógica é falha.
CarLuva
9
@CarLuva A seção POST diz "O método POST é usado para solicitar que o servidor de origem aceite a entidade fechada ..." A seção do corpo da entidade diz "O corpo da entidade é obtido do corpo da mensagem ..." Portanto, o A seção POST menciona o corpo da mensagem, embora indiretamente fazendo referência ao corpo da entidade que é transportado pelo corpo da mensagem da solicitação POST.
Frederickf
9

De acordo com XMLHttpRequest, não é válido. Do padrão :

4.5.6 O send()método

client . send([body = null])

Inicia a solicitação. O argumento opcional fornece o corpo da solicitação. O argumento será ignorado se o método de solicitação for GETou HEAD.

Lança uma InvalidStateErrorexceção se um estado não estiver aberto ou o send()sinalizador estiver definido.

O método deve executar estas etapas:send(body)

  1. Se o estado não estiver aberto , lance uma InvalidStateErrorexceção.
  2. Se o send()sinalizador estiver definido, lance uma InvalidStateErrorexceção.
  3. Se o método de solicitação for GETou HEAD, defina body como null.
  4. Se o corpo for nulo, vá para a próxima etapa.

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á.

Rafael Sales
fonte
1
diminuiu o voto devido ao fato de XMLHttpRequest ser uma implementação. Pode não refletir a especificação real que ele deve implementar.
floum
10
O voto negativo acima está errado, se algumas implementações não suportarem o envio de um corpo com um GET, esse pode ser um motivo para não fazê-lo, independentemente da especificação. Na verdade, eu me deparei com esse problema exato em um produto de plataforma cruzada em que estou trabalhando - apenas a plataforma que usa XMLHttpRequest falhou ao enviar o get.
Pjcard #
8

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>.

gertas
fonte
Acho que é uma péssima ideia :) Mas, se fizesse algo assim, usaria um cabeçalho HTTP personalizado (e certifique-se de sempre enviar de volta o Vary: na resposta).
Evert
Ruim ou não, mas factível :) Com os dados no cabeçalho, há um problema semelhante com o tamanho dos dados, consulte stackoverflow.com/questions/686217/… . No entanto, obrigado por mencionar o Varycabeçalho, eu não estava ciente de seu potencial real.
gertas
6

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.

cloudhead
fonte
5

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.

chaz
fonte
Você pode enviar qualquer parâmetro que desejar com o x-prefixo; quaisquer limites no comprimento dos cabeçalhos seriam inteiramente um limite arbitrário do servidor.
Chris Marisic
4

Estou chateado que REST como protocolo não suporta OOP e Getmé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

var client = new JsonServiceClient(Settings.Default.ServiceAddress);
var request = new GetClientRequest
    {
        Id = new Guid("2217239b0e-b35b-4d32-95c7-5db43e2bd573")
    };
var response = client.Get<GetClientRequest, ClientResponse>(request);

as you can see, the GetClientRequest was encoded to the following query string

http://localhost/clients/GetWithResponse?type=GetClientRequest&data=%7B%22Id%22:%2217239b0e-b35b-4d32-95c7-5db43e2bd573%22%7D
GSerjo
fonte
8
Você deve apenas usar o POST. Se houver um nome de método no URL, você estará violando o design de descanso fundamental. Este é RPC, use POST.
Evert
3
Eu não acho que isso seja grande coisa, temos mais problemas durante o desenvolvimento com o URL RESTful (ou seja, orders / 1). Quanto a mim, algo errado com o método Get, é incompatível com OOP. E quem se importa com a aparência do URL :) Mas com a abordagem baseada em mensagens, podemos criar uma interface remota estável e isso é realmente importante. PS não é RPC, é mensagem com base
GSerjo
3
Eu acho que você está perdendo todo o objetivo do REST. Quando você diz, quem se importa com a aparência do URL, bem, o REST se importa muito. E por que o REST seria compatível com o OOP?
shmish111
Não, eu não acabei de ver um pouco mais longe
GSerjo 18/12/2015
4

Por exemplo, ele funciona com Curl, Apache e PHP.

Arquivo PHP:

<?php
echo $_SERVER['REQUEST_METHOD'] . PHP_EOL;
echo file_get_contents('php://input') . PHP_EOL;

Comando do console:

$ curl -X GET -H "Content-Type: application/json" -d '{"the": "body"}' 'http://localhost/test/get.php'

Resultado:

GET
{"the": "body"}
mnv
fonte
Experiência divertida! O PHP lerá apenas $_POSTquando o corpo for enviado com uma solicitação POST e application/x-www-form-urlencoded. Isso significa que o corpo é ignorado em uma GETsolicitação. Neste caso: $_GETe $_POSTsão muito enganadores de qualquer maneira neste momento. Então uso melhor #php://input
Martin Muzatko
3

IMHO, você pode simplesmente enviar o JSONcodificado (ou seja, encodeURIComponent) da URLmaneira que você não violar as HTTPespecificações e levá JSON-lo ao servidor.

EthraZa
fonte
28
Sim, mas a questão principal é o limite de comprimento, como lidamos com isso?
Sebas 28/03
2

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:

  1. Use cadeias de consulta, por exemplo example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
  2. Use mod_rewrite (ou similar) para caminhos: example.com/category/{catid}/item/{itemid}/{sortby}/{order}
  3. Use cabeçalhos HTTP individuais que você passa com a solicitação
  4. Use um método diferente, por exemplo, POST, para recuperar um recurso.

Todos têm suas desvantagens, mas são muito melhores do que usar um GET com um corpo.

Xenonite
fonte
0

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 :

Se uma GETsolicitação do visualizador incluir um corpo, o CloudFront retornará um código de status HTTP 403 (Proibido) ao visualizador.

E sim, suas bibliotecas cliente também podem não suportar a emissão de tais solicitações, conforme relatado neste comentário .

Frédéric
fonte
0

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:

// SimpleClientHttpRequestFactory.class
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory {
    ...
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        ...
        if (!"POST".equals(httpMethod) && !"PUT".equals(httpMethod) && !"PATCH".equals(httpMethod) && !"DELETE".equals(httpMethod)) {
            connection.setDoOutput(false);
        } else {
            connection.setDoOutput(true);
        }
        ...
    }
}

// SimpleBufferingClientHttpRequest.class
final class SimpleBufferingClientHttpRequest extends AbstractBufferingClientHttpRequest {
    ...
    protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
        ...
        if (this.connection.getDoOutput() && this.outputStreaming) {
            this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
        }

        this.connection.connect();
        if (this.connection.getDoOutput()) {
            FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
        } else {
            this.connection.getResponseCode();
        }
        ...
    }
}

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.

Zhou
fonte
Você não está lendo as especificações ou os comentários aqui corretamente. Clientes e servidores que eliminam o corpo da solicitação estão dentro das especificações. Não use corpos de solicitação GET.
Evert
@Evert Eu não li os comentários corretamente ou você não? :) Se você rolar até a resposta de Paul Morgan (a resposta mais acertada) e ler os comentários com atenção, você encontrará o seguinte: "O RFC2616 mencionado como" especificação HTTP / 1.1 "está obsoleto. Em 2014, foi substituído por RFCs 7230-7237. A citação "o corpo da mensagem DEVE ser ignorado 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. ... "
Zhou
@Evert Além disso, eu estava usando o utilitário de teste REST "com certeza" para testar meu back-end de inicialização Spring. O servidor, com certeza e com inicialização por mola, manteve o corpo do Json para a solicitação GET! Somente o RestTemplate da estrutura Sping descarta o corpo das solicitações GET; portanto, Spring-boot, tenha certeza e RestTemplate, o que está / está errado?
Zhou
@Evert Por último, mas não conceder, eu não pedi que as pessoas usassem body em solicitações GET, pelo contrário, sugeri NÃO fazê-lo analisando o código-fonte do RestTemplate do Sping-framework, então por que você votou negativamente no meu responda?
Zhou
Não diminuí a votação da sua resposta. Só estou esclarecendo que qualquer implementação HTTP que solte a solicitação GET está na especificação.
Evert