Pergunta

Estou desenvolvendo um novo webservice REST para a nossa aplicação.

Ao fazer um GET em determinadas entidades, os clientes podem solicitar o conteúdo da entidade. Se eles querem adicionar alguns parâmetros (por exemplo, ordenar uma lista) podem adicionar esses parâmetros na cadeia de consulta.

Como alternativa eu ??quero que as pessoas sejam capazes de especificar esses parâmetros no corpo da solicitação. HTTP / 1.1 não parece proibir explicitamente isso. Isto irá permitir-lhes para especificar mais informações, pode tornar mais fácil para especificar solicitações XML complexos.

As minhas perguntas:

  • Será esta uma boa idéia completamente?
  • Será HTTP clientes têm problemas com o uso de corpos pedido no prazo de um pedido GET?

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

Foi útil?

Solução

O comentário de

Roy Fielding sobre a inclusão de um corpo com um pedido GET .

Sim. Em outras palavras, qualquer mensagem de solicitação HTTP é permitido para conter um corpo de mensagem, e, portanto, deve analisar mensagens com isso em mente. semântica de servidor para GET, no entanto, são restritas de tal forma que um corpo, se houver, não tem significado semântico ao pedido. Os requisitos em análise são separados dos requisitos de semântica do método.

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

Esta é parte do projeto em camadas de HTTP / 1.1 que se tornará limpar novamente uma vez que a especificação é particionado (work in progress).

.... Roy

Sim, você pode enviar um corpo de solicitação com GET, mas não deve ter qualquer significado. Se você dar-lhe significado por analisá-lo no servidor e mudar a sua resposta com base em seu conteúdo , então você está ignorando esta recomendação em o HTTP / 1.1 especificação, secção 4.3 :

[...] se o método de solicitação não inclui semântica definida para uma entidade-corpo, então o mensagem-corpo DEVE ser ignorado ao manusear a solicitação.

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

Os meios método GET recupera qualquer informação ([...]) é identificado pelo Request-URI.

que afirma que o pedido de corpo não é parte da identificação do recurso em uma solicitação GET, apenas o pedido URI.

Atualizar A RFC2616 referenciada como "HTTP / 1.1 spec" é agora obsoleto. Em 2014 foi substituído pelo RFCs 7230-7237. Citamos "a mensagem-corpo deve ser ignorado ao manusear a solicitação" foi eliminada. Agora é apenas "mensagem de solicitação de enquadramento é independente da semântica do método, mesmo que o método não define qualquer uso para um corpo mensagem" A segunda citação "O método GET meios recuperar qualquer informação ... é identificado pelo Request-URI" Foi apagado. - A partir de um comentário

Outras dicas

Enquanto você pode fazer isso, na medida em que não é explicitamente excluída pela especificação HTTP, gostaria de sugerir evitando-lo simplesmente porque as pessoas não esperar que as coisas funcionam assim. Há muitas fases em uma cadeia de solicitação HTTP e enquanto eles "principalmente" em conformidade com a especificação HTTP, a única coisa que você tem a garantia é que eles irão se comportar como tradicionalmente usado pelos navegadores web. (Estou pensando em coisas como proxies transparentes, aceleradores, toolkits A / V, etc.)

Este é o espírito por trás da Robustez Princípio aproximadamente "ser liberal no que você aceitar, e conservador no que você enviar", você não quer empurrar os limites de uma especificação sem uma boa razão.

No entanto, se você tem uma boa razão, ir para ele.

Você provavelmente vai encontrar problemas se você tentar tirar vantagem de caching. Proxies não estão indo olhar no corpo começa a ver se os parâmetros têm um impacto sobre a resposta.

Nem restclient nem consola RESTO suportar isso, mas onda faz.

O HTTP especificação diz na secção 4.3

Uma mensagem-corpo não devem ser incluídos em uma solicitação se a especificação do método de solicitação (seção 5.1.1) não permite o envio de uma entidade-corpo em pedidos.

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 de mensagem. No entanto ...

Seção 5.2 diz

O recurso exata identificado por um pedido Internet é determinada examinando tanto o Request-URI e do campo de cabeçalho host.

Seção 9.3 diz

O GET meios método obter qualquer informação (na forma de uma entidade) é identificado pelo Request-URI.

que juntos sugerem que ao processar um pedido GET, um servidor não é necessário para examinar qualquer outra coisa que o Request-URI e campo de cabeçalho host.

Em resumo, o HTTP especificação não impedir o envio de uma mensagem-corpo com GET, mas não há ambiguidade suficiente que não seria surpresa para mim se ele não foi apoiada por todos os servidores.

ElasticSearch aceita solicitações GET com um corpo. Parece mesmo que esta é a maneira preferida: http: // www. elasticsearch.org/guide/en/elasticsearch/reference/current/common-options.html#_request_body_in_query_string

Algumas bibliotecas cliente (como o motorista do rubi) pode registrar o comando grito para stdout no modo de desenvolvimento e está usando esta sintaxe extensivamente.

O que você está tentando alcançar foi feito por um longo tempo com um método muito mais comum, e que não depende de usando uma carga útil com GET.

Você pode simplesmente construir a sua procura específica mediatype, ou se você quiser ser mais RESTful, use algo como OpenSearch e POST a solicitação para o URI do servidor instruído, digamos / search. O servidor pode, então, gerar o resultado de pesquisa ou construir o URI final e redirecionar usando um 303.

Isto tem a vantagem de seguir o método PRG tradicional, ajuda intermediários Cache Cache os resultados, etc.

Dito isso, URIs são codificadas de qualquer maneira para qualquer coisa que não é ASCII, e por isso são application / x-www-form-urlencoded e multipart / form-data. Eu recomendo usar isso em vez de criar mais um formato JSON personalizado se a sua intenção é apoiar cenários repousante.

Você pode enviar um GET com um corpo ou enviar um POST e desistir religiosidade RESTish (não é tão ruim, 5 anos atrás, houve apenas um membro de que a fé - seus comentários ligada acima).

Nem são grandes decisões, mas o envio de um corpo GET pode evitar problemas para alguns clientes - e alguns servidores.

Fazendo um POST pode ter obstáculos com algumas estruturas RESTish.

Julian Reschke sugerido acima usando um não-padrão cabeçalho HTTP como "SEARCH", que poderia ser uma solução elegante, exceto que é ainda menos provável a ser suportado.

Pode ser mais produtivo para os clientes de lista que pode e não pode fazer cada um dos acima.

Os clientes que não podem enviar um GET com o corpo (que eu saiba):

  • XmlHTTPRequest Fiddler

Os clientes que podem enviar um GET com o corpo:

  • a maioria dos navegadores

Servidores e bibliotecas que podem recuperar um corpo de GET:

  • Apache
  • PHP

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

  • ?

Qual servidor irá ignorá-lo? - fijiaaron 30 '12 agosto em 21:27

Google , por exemplo, está fazendo pior do que ignorá-lo, ele vai considerá-lo um Erro !

Tente você mesmo com um netcat simples:

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

1234

(o conteúdo 1234 é seguido por CR-LF, de modo que é de um total de 6 bytes)

e você obterá:

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 obter 400 Bad Pedido de Bing, da Apple, etc ... que são servidos por AkamaiGhost.

Então, eu não aconselharia usando requisições GET com uma entidade corpo.

A partir 2616, secção 4.3 , "Message Body":

Um servidor deve ler e enviar uma mensagem-corpo em qualquer solicitação; se o método de solicitação não inclui semântica definida para uma entidade-corpo, em seguida, a mensagem-corpo deve ser ignorado ao manusear a solicitação.

Isto é, os servidores devem sempre ler qualquer corpo da solicitação fornecida a partir da rede (verifique Content-Length ou ler um corpo Chunked, etc). Além disso, proxies deve encaminhar tal órgão pedido que recebem. Então, se o RFC define semântica para o corpo para o método dado, o servidor pode realmente usar o corpo da solicitação para gerar uma resposta. No entanto, se o RFC não definem a semântica para o corpo, em seguida, o servidor deve ignorá-lo.

Isto está de acordo com as citações de Fielding acima.

Seção 9.3 , "GET", descreve a semântica do método GET, e não faz mencionar corpos de solicitação. Portanto, um servidor deve ignorar qualquer corpo da solicitação recebe sobre um pedido GET.

Eu coloquei esta questão para o IETF HTTP WG. O comentário de Roy Fielding (autora de HTTP / 1.1 documento em 1998) foi que

"... uma implementação seria quebrado para fazer outra coisa senão para analisar e descartar que o corpo se recebeu"

RFC 7213 (HTTPbis) estados:

"A carga útil dentro de uma mensagem de solicitação GET tem semântica não definido";

Parece claro agora que a intenção era que significado semântico sobre os corpos de pedidos GET é proibida, o que significa que o corpo da solicitação não pode ser usada para afetar o resultado.

Existem proxies lá fora, que vai definitivamente quebrar o seu pedido de várias maneiras, se você incluir um corpo em GET.

Então, em resumo, não fazê-lo.

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

4.5.6 O método send()

client . send([body = null])

Inicia o pedido. O argumento opcional fornece o pedido corpo. O argumento é ignorado se método de solicitação é GET ou HEAD.

Lança uma exceção InvalidStateError se qualquer Estado não é aberto ou a bandeira send() está definido.

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

  1. Se o estado não é aberto , lançar uma exceção InvalidStateError.
  2. Se o sinalizador send() está definido, lançar uma exceção InvalidStateError.
  3. Se o método de solicitação é GET ou HEAD, conjunto de corpo para null.
  4. Se corpo é nulo, vá para o passo seguinte.

Embora, eu não acho que deveria porque solicitação GET pode precisar o conteúdo do corpo grande.

Então, se você contar com XMLHttpRequest de um navegador, é provável que ele não vai funcionar.

Se você realmente quer enviar cachable JSON corpo / XML para aplicações web o lugar razoável para colocar os seus dados estão query string codificada com RFC4648: base 64 Codificação com URL e nome do arquivo do alfabeto Seguro . Claro que você poderia apenas urlencode JSON e colocar é no valor de URL do param, mas Base64 dá menor resultado. Tenha em mente que existem restrições de tamanho de URL, consulte Qual é o comprimento máximo de um URL em diferentes navegadores? .

Você pode pensar que o personagem preenchimento = de Base64 pode ser ruim para o valor param de URL, no entanto, não parece - 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 param name porque string codificada com estofamento será interpretado como chave param com valor vazio. Gostaria de usar algo como ?_b64=<encodeddata>.

Eu não aconselharia isso, ela vai contra as práticas padrão, e não oferece muito em troca. Você deseja manter o corpo de conteúdo, e não opções.

E a não-conformidade do base64 cabeçalhos codificados? "SOMETHINGAPP-PARAMS: sdfSD45fdg45 / como"

restrições de comprimento hm. você não pode fazer o seu manuseio pós distinguir entre os significados? Se você quiser parâmetros simples, como classificação, não vejo por que isso seria um problema. Eu acho que é certeza que você está preocupado.

Estou chateado que descansar o protocolo não suporta OOP e método Get é a prova. Como solução, você pode serializar seu um DTO para JSON e, em seguida, criar uma string de consulta. No lado do servidor você vai capaz de desserializar a string de consulta ao DTO.

Dê uma olhada em:

abordagem baseada mensagem pode ajudá-lo a resolver Obter restrição método. Você vai capaz de enviar qualquer DTO como com pedido corpo

Nelibur quadro serviço web fornece a 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

IMHO você poderia simplesmente enviar o JSON codificada (ie. encodeURIComponent) na URL, desta forma você não violam as especificações HTTP e obter o seu JSON para o servidor.

Por exemplo, trabalha com Curl, Apache e PHP.

arquivo PHP:

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

comando Console:

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

Output:

GET
{"the": "body"}

Você tem uma lista de opções que são muito melhor do que usar um corpo de solicitação com GET.

Let' assumir que tem categorias e itens para cada categoria. Tanto a ser identificado por um id ( "catid" / "ItemId" por causa deste exemplo). Você deseja classificar de acordo com um outro parâmetro "SortBy" em uma "ordem" específico. Você quer passar parâmetros para "SortBy" e "ordem":

Você pode:

  1. Use seqüências 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. Usar cabeçalhos HTTP indivíduo você passa com o pedido
  4. Use um método diferente, por exemplo, POST, para recuperar um recurso.

Todos têm as suas desvantagens, mas é muito melhor do que usar um GET com um corpo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top