HTTP GET con il corpo della richiesta


2111

Sto sviluppando un nuovo servizio web RESTful per la nostra applicazione.

Quando si esegue un OTTENERE su determinate entità, i clienti possono richiedere il contenuto dell'entità. Se desiderano aggiungere alcuni parametri (ad esempio l'ordinamento di un elenco) possono aggiungere questi parametri nella stringa di query.

In alternativa, desidero che le persone siano in grado di specificare questi parametri nel corpo della richiesta. HTTP / 1.1 non sembra vietarlo esplicitamente. Ciò consentirà loro di specificare più informazioni, potrebbe rendere più semplice specificare richieste XML complesse.

Le mie domande:

  • È una buona idea del tutto?
  • I client HTTP avranno problemi con l'utilizzo degli organismi di richiesta all'interno di una richiesta GET?

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


553
Il vantaggio è che consente di inviare facilmente corpi di richieste XML o JSON, non ha limiti di lunghezza ed è più facile da codificare (UTF-8).
Evita il

29
Se quello che stai cercando è un metodo sicuro e idempotente che consenta agli organismi di richiesta, potresti cercare CERCA, PROPFIND e REPORT. Ovviamente non usando GET e avendo una richiesta il corpo sconfigge più o meno la cache.
Julian Reschke,

226
@fijiaaron: Sono passati 3 anni e da allora ho acquisito una vasta esperienza nella scrittura di servizi web. Fondamentalmente è tutto ciò che ho fatto negli ultimi anni. Posso tranquillamente dire che è davvero una pessima idea aggiungere un corpo a una richiesta GET. Le prime due risposte stanno come una roccia.
Evert

26
@Ellesedil: In poche parole: qualunque sia il vantaggio che deriva dall'utilizzo di GET su POST, esiste a causa della progettazione dell'HTTP. Questi vantaggi non esistono più quando si viola lo standard in questo modo. Pertanto è rimasto solo un motivo per utilizzare GET + un corpo di richiesta anziché POST: Estetica. Non sacrificare il design robusto per l'estetica.
Evert

7
Per sottolineare ciò che ha detto Evert: "non ha limiti di lunghezza". Se il tuo GET con i parametri della query sta infrangendo la limitazione della lunghezza (di 2048), allora quale altra scelta c'è oltre a mettere le informazioni sulla stringa di query in un oggetto json, ad esempio, nel corpo della richiesta.
Kieran Ryan,

Risposte:


1726

Il commento di Roy Fielding sull'inclusione di un corpo con una richiesta GET .

Sì. In altre parole, qualsiasi messaggio di richiesta HTTP può contenere un corpo di messaggio e quindi deve analizzare i messaggi tenendo presente questo. La semantica del server per GET, tuttavia, è limitata in modo tale che un corpo, se presente, non ha alcun significato semantico per la richiesta. I requisiti sull'analisi sono separati dai requisiti sulla semantica del metodo.

Quindi, sì, puoi inviare un corpo con GET, e no, non è mai utile farlo.

Questo fa parte del design a strati di HTTP / 1.1 che diventerà di nuovo chiaro una volta che le specifiche saranno partizionate (lavori in corso).

.... Roy

Sì, puoi inviare un corpo di richiesta con GET ma non dovrebbe avere alcun significato. Se gli dai un significato analizzandolo sul server e modificando la tua risposta in base al suo contenuto , stai ignorando questa raccomandazione nelle specifiche HTTP / 1.1, sezione 4.3 :

[...] se il metodo di richiesta non include la semantica definita per un corpo-entità, il corpo del messaggio DOVREBBE essere ignorato quando si gestisce la richiesta.

E la descrizione del metodo GET nelle specifiche HTTP / 1.1, sezione 9.3 :

Il metodo GET significa recuperare qualsiasi informazione ([...]) identificata dall'URI di richiesta.

che afferma che il corpo della richiesta non fa parte dell'identificazione della risorsa in una richiesta GET, ma solo l'URI della richiesta.

Aggiornamento L'RFC2616 indicato come "Specifica HTTP / 1.1" è ora obsoleto. Nel 2014 è stato sostituito dagli RFC 7230-7237. La citazione "il corpo del messaggio DOVREBBE essere ignorato durante la gestione della richiesta" è stata eliminata. Ora è solo "Richiedi l'inquadramento dei messaggi è indipendente dalla semantica del metodo, anche se il metodo non definisce alcun uso per un corpo del messaggio" La seconda citazione "Il metodo GET significa recuperare qualsiasi informazione ... identificata dall'URI di richiesta" è stato cancellato. - Da un commento


72
La memorizzazione nella cache / il proxy sono le due cose che probabilmente si rompono, sì. "Semantica" è solo un altro modo di dire "il modo in cui le persone che producono altri componenti si aspetteranno che funzionino altri componenti". Se si viola la semantica, è più probabile che le cose si rompano nei luoghi in cui le persone hanno scritto cose che si aspettavano che tu onorassi quella semantica.
Stuart P. Bentley,

109
Elasticsearch è un prodotto abbastanza importante che utilizza i corpi di richiesta HTTP in GET. Secondo il loro manuale, se una richiesta HTTP dovrebbe supportare o meno un corpo non è definita. Personalmente non mi sento a mio agio nel popolare un corpo di richiesta GET, ma sembrano avere un'opinione diversa e devono sapere cosa stanno facendo. elastic.co/guide/en/elasticsearch/guide/current/…
GordonM

26
@iwein dando corpi richiesta GET senso è in realtà non è una violazione della specifica. HTTP / 1.1 specifica che i server DOVREBBERO ignorare il corpo, ma RFC 2119 specifica che gli implementatori possono ignorare le clausole "DOVREBBE" se hanno buone ragioni per farlo. Piuttosto, un client non violare le specifiche, se si assume che cambiando il corpo GET sarà non modificare la risposta.
Emil Lundberg,

108
L'RFC2616 indicato come "specifica HTTP / 1.1" è ora obsoleto. Nel 2014 è stato sostituito dagli RFC 7230-7237. La citazione " il corpo del messaggio DOVREBBE essere ignorato durante la gestione della richiesta " è stata eliminata . Ora è solo " Richiedi l'inquadramento dei messaggi è indipendente dalla semantica del metodo, anche se il metodo non definisce alcun uso per un corpo del messaggio " La seconda citazione " Il metodo GET significa recuperare qualsiasi informazione ... identificata dall'URI di richiesta " è stato cancellato . Quindi, suggerisco di modificare la risposta @Jarl
Artem Nakonechny il

29
So che è un vecchio filo - ci sono inciampato su di esso. @Artem Nakonechny ha tecnicamente ragione, ma la nuova specifica dice "Un payload all'interno di un messaggio di richiesta GET non ha una semantica definita; l'invio di un corpo di payload su una richiesta GET potrebbe causare il rifiuto di alcune implementazioni esistenti". Quindi non è ancora una buona idea se può essere evitato.
orologio rapido

290

Mentre puoi farlo, nella misura in cui non è esplicitamente escluso dalla specifica HTTP, suggerirei di evitarlo semplicemente perché le persone non si aspettano che le cose funzionino in quel modo. Esistono molte fasi in una catena di richieste HTTP e sebbene siano "per lo più" conformi alle specifiche HTTP, l'unica cosa che ti viene assicurata è che si comporteranno come tradizionalmente usato dai browser web. (Sto pensando a cose come proxy trasparenti, acceleratori, toolkit A / V, ecc.)

Questo è lo spirito alla base del principio di robustezza all'incirca "sii liberale in ciò che accetti e conservatore in ciò che invii", non vuoi spingere i confini di una specifica senza una buona ragione.

Tuttavia, se hai una buona ragione, provaci.


229
Il principio di robustezza è imperfetto. Se sei liberale in ciò che accetti, otterrai merda, se avrai successo in termini di adozione, solo perché accetti la merda. Ciò renderà più difficile l'evoluzione della tua interfaccia. Guarda HTML. Questo è il principio di reboustness in azione.
Eugene Beresovsky,

28
Penso che il successo e l'ampiezza dell'adozione (e dell'abuso) dei protocolli parli del valore del principio di solidità.
caskey,

39
Hai mai provato ad analizzare il vero HTML? Non è possibile implementarlo da soli, ecco perché quasi tutti - inclusi i giocatori veramente grandi come Google (Chrome) e Apple (Safari), non lo hanno fatto ma si sono affidati a implementazioni esistenti (alla fine si sono affidati tutti al KHTML di KDE). Quel riutilizzo è ovviamente carino, ma hai provato a visualizzare html in un'applicazione .net? È un incubo, poiché devi incorporare un componente IE (o non gestito), o simile, con i suoi problemi e crash, oppure usi il componente gestito disponibile (su codeplex) che non ti consente nemmeno di selezionare il testo.
Eugene Beresovsky,

6
Non solo le specifiche HTTP consentono i dati del corpo con la richiesta GET, ma questa è anche pratica comune: l'API _search del popolare motore ElasticSearch consiglia le richieste GET con la query allegata in un corpo JSON. Come concessione a implementazioni client HTTP incomplete, consente anche richieste POST qui.
Christian Pietsch,

4
@ChristianPietsch, è pratica comune oggi. Quattro anni fa non lo era. Mentre la specifica consente esplicitamente a un client di includere facoltativamente (MAY) un'entità in una richiesta (sezione 7), il significato di MAY è definito in RFC2119 e un server proxy (scadente) potrebbe essere conforme alle specifiche mentre si rimuovono le entità nelle richieste GET, in particolare finché non si arresta in modo anomalo, può fornire una "funzionalità ridotta" inoltrando le intestazioni della richiesta e non l'entità inclusa. Allo stesso modo ci sono una serie di regole su quali modifiche alla versione DEVONO essere / DOVREBBE / DOVREBBE essere apportate quando si esegue il proxy tra i diversi livelli di protocollo.
caskey,

151

Probabilmente incontrerai problemi se proverai a sfruttare la cache. I proxy non guarderanno nel corpo GET per vedere se i parametri hanno un impatto sulla risposta.


10
L'uso dei campi di intestazione ETag / Last-Modified aiuta in questo modo: quando viene utilizzato un "GET condizionale", i proxy / cache possono agire su queste informazioni.
jldupont,

2
@jldupont Le cache utilizzano la presenza di validatori per sapere se una risposta non valida può essere riconvalidata, tuttavia non vengono utilizzati come parte della chiave cache primaria o secondaria.
Darrel Miller,

Potresti risolverlo con un checksum del corpo in un parametro di query
Adrian

73

restclientconsole REST supportano questo, ma curl non lo fa.

Le specifiche HTTP sono riportate nella sezione 4.3

Un corpo di messaggio NON DEVE essere incluso in una richiesta se la specifica del metodo di richiesta (sezione 5.1.1) non consente l'invio di un corpo di entità nelle richieste.

La sezione 5.1.1 ci reindirizza alla sezione 9.x per i vari metodi. Nessuno di loro proibisce esplicitamente l'inclusione di un corpo del messaggio. Però...

La sezione 5.2 dice

La risorsa esatta identificata da una richiesta Internet viene determinata esaminando sia il campo dell'intestazione URI richiesta sia quello Host.

e dice la Sezione 9.3

Il metodo GET significa recuperare qualsiasi informazione (sotto forma di entità) identificata dall'URI di richiesta.

Che insieme suggeriscono che quando elabora una richiesta GET, un server non è tenuto ad esaminare altro che il campo dell'intestazione Request-URI e Host.

In breve, le specifiche HTTP non ti impediscono di inviare un corpo di messaggio con GET ma c'è un'ambiguità sufficiente da non sorprendermi se non fosse supportato da tutti i server.


2
La zampa ha anche l'opzione per supportare le richieste GET con i corpi ma deve essere abilitata nelle impostazioni.
s

"Il metodo GET significa recuperare qualsiasi informazione (sotto forma di entità) identificata dall'URI di richiesta." Quindi, è tecnicamente illegale / sbagliato avere un endpoint GET che ottiene tutte le entità? Ad esempio, GET /contacts/100/addressesrestituisce una raccolta di indirizzi per la persona con id=100.
Josh M.

La libreria Java sicura per il test delle API REST non supporta la richiesta GET con un corpo. Anche Apache HttpClient non lo supporta.
Paulo Merson,

Django supporta anche l'analisi di un corpo GET
Bruno Finger,

60

Elasticsearch accetta le richieste GET con un ente. Sembra persino che questo sia il modo preferito: la guida di Elasticsearch

Alcune librerie client (come il driver Ruby) possono registrare il comando cry su stdout in modalità di sviluppo e sta usando questa sintassi ampiamente.


5
Mi chiedevo perché Elasticsearch lo permettesse. Ciò significa che questa query per contare tutti i documenti con carico utile ad una richiesta GET curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }' è equivalente compreso il carico utile come sourceparam: curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
Arun

40
Le query complesse possono raggiungere la lunghezza massima dell'intestazione http.
s

11
Stava leggendo la documentazione di elasticsearch che mi ha portato a questa domanda poiché pensavo che fosse considerata una cattiva pratica includere un corpo
PatrickWalker,

1
Non è nemmeno necessario che sia una query complessa. Anche un semplice scorrimento può restituire un scroll_id molto lungo (in un cluster con molti frammenti), che porterà a superare la lunghezza massima dell'URL se aggiunto lì.
Brent Hronik,

11
Elasticsearch supporta la stessa richiesta utilizzando POST. Hanno scelto di consentire un corpo in un GET perché hanno ritenuto che un GET fosse più semanticamente corretto di un POST quando si tratta di interrogare i dati. È divertente che Elasticsearch sia menzionato così tanto in questa discussione. Non vorrei usare un esempio (anche se da un prodotto popolare) come motivo per seguire la pratica.
DSO

33

Quello che stai cercando di ottenere è stato fatto a lungo con un metodo molto più comune e uno che non si basa sull'utilizzo di un payload con GET.

Puoi semplicemente costruire il tuo specifico tipo di media di ricerca, o se vuoi essere più RESTful, usare qualcosa come OpenSearch e POST la richiesta all'URI indicato dal server, dì / cerca. Il server può quindi generare il risultato della ricerca o creare l'URI finale e reindirizzare utilizzando un 303.

Questo ha il vantaggio di seguire il tradizionale metodo PRG, aiuta gli intermediari nella cache a memorizzare i risultati, ecc.

Detto questo, gli URI sono comunque codificati per tutto ciò che non è ASCII, così come lo sono application / x-www-form-urlencoded e multipart / form-data. Consiglierei di utilizzare questo invece di creare un altro formato json personalizzato se la tua intenzione è supportare scenari ReSTful.


4
Puoi semplicemente costruire il tuo mediatype di ricerca specifico che potresti elaborare?
Piotr Dobrogost,

2
Con ciò stavo dicendo che potresti creare un tipo di supporto chiamato application / vnd.myCompany.search + json che conterrebbe il tipo di modello di ricerca che desideri che un client emetta, e il cliente potrebbe quindi inviarlo come POST. Come ho sottolineato, esiste già un tipo di supporto per questo e si chiama OpenSearch, il riutilizzo di un tipo di supporto esistente dovrebbe essere scelto sul percorso personalizzato quando è possibile implementare lo scenario con standard esistenti.
SerialSeb,

14
È intelligente, ma eccessivamente complesso e inefficiente. Ora devi inviare un POST con i tuoi criteri di ricerca, ottenere un URI come risposta dal tuo POST, quindi inviare un GET con l'URI dei criteri di ricerca al server per inviarlo ai GET i criteri e rispedirti il ​​risultato. (Tranne il fatto che includere un URI in un URI è tecnicamente impossibile perché non è possibile inviare qualcosa che può contenere fino a 255 caratteri all'interno di qualcosa che non può essere più di 255 caratteri, quindi è necessario utilizzare un identificatore parziale e il server quindi deve sapere come risolvere l'URI per i criteri di ricerca postati.)
fijiaaron

30

Puoi inviare un OTTENERE con un corpo o inviare un POST e rinunciare alla religiosità RESTOSA (non è poi così male, 5 anni fa c'era solo un membro di quella fede - i suoi commenti collegati sopra).

Né sono grandi decisioni, ma l'invio di un corpo GET può prevenire problemi per alcuni client e alcuni server.

Fare un POST potrebbe avere degli ostacoli con alcuni framework RESTish.

Julian Reschke ha suggerito sopra usando un'intestazione HTTP non standard come "SEARCH" che potrebbe essere una soluzione elegante, tranne per il fatto che è ancora meno probabile che sia supportata.

Potrebbe essere più produttivo elencare i client che possono e non possono fare ciascuno dei precedenti.

Clienti che non possono inviare un GET con body (di cui sono a conoscenza):

  • XmlHTTPRequest Fiddler

Clienti che possono inviare un GET con body:

  • la maggior parte dei browser

Server e librerie che possono recuperare un corpo da OTTENERE:

  • Apache
  • PHP

Server (e proxy) che rimuovono un corpo da GET:

  • ?

2
Squid 3.1.6 rimuove anche i corpi GET quando Content-Length è 0 o non impostato, e in caso contrario restituisce una lunghezza HTTP 411 richiesta anche se la lunghezza è impostata
rkok

2
Fiddler lo farà, ma ti avverte.
toddmo il

Stai dicendo che un SEARCHmetodo potrebbe spezzarsi lungo la strada? Se i proxy non capiscono un metodo, sono tenuti a passarlo così com'è, quindi non sono troppo sicuro del motivo per cui pensi che possa rompere qualcosa ...
Alexis Wilke,

22

Ho posto questa domanda al WG HTTP IETF. Il commento di Roy Fielding (autore del documento http / 1.1 nel 1998) è stato quello

"... un'implementazione verrebbe interrotta per fare altro che analizzare e scartare quell'organismo se ricevuto"

RFC 7213 (HTTPbis) afferma:

"Un payload all'interno di un messaggio di richiesta GET non ha una semantica definita;"

Sembra chiaro ora che l'intenzione era che il significato semantico sui corpi di richiesta GET fosse proibito, il che significa che il corpo di richiesta non può essere usato per influenzare il risultato.

Ci sono proxy là fuori che sicuramente interromperanno la tua richiesta in vari modi se includi un body su GET.

Quindi in sintesi, non farlo.


21

Quale server lo ignorerà? - fijiaaron, 30 agosto 12 alle 21:27

Google, ad esempio, sta facendo peggio che ignorarlo, lo considererà un errore !

Provalo tu stesso con un semplice netcat:

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

1234

(il contenuto 1234 è seguito da CR-LF, per un totale di 6 byte)

e otterrai:

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.

Ricevi anche 400 richieste non valide da Bing, Apple, ecc ... che sono servite da AkamaiGhost.

Quindi non consiglierei di usare le richieste GET con un'entità corporea.


65
Questo esempio è inutile perché di solito quando le persone aggiungono il corpo alle GETrichieste, è perché il loro server personalizzato è in grado di gestirlo. La domanda quindi è se le altre "parti mobili" (browser, cache, ecc.) Funzioneranno correttamente.
Pacerier,

6
Si tratta di richieste errate perché il payload non è previsto (o ragionevole) per un GET determinato endpoint : non ha nulla a che fare con l'uso del GETcaso generale. Un payload casuale potrebbe rompersi POSTaltrettanto facilmente e restituire lo stesso 400 Bad Request, se i contenuti non fossero in un formato sensato nel contesto della richiesta specifica.
nobar,

E non solo sull'endpoint nel suo insieme, ma piuttosto su quell'URL specifico .
Lawrence Dol,

1
Questo è irrilevante perché è solo l'implementazione del server di Google a quell'URL. Quindi non ha senso la domanda
Joel Duckworth,

per me è stato utile, poiché stavo cercando di utilizzare le funzioni Firebase con una richiesta get + body, e questo errore può essere molto criptico e difficile da capire.
scrimau,

19

Da RFC 2616, sezione 4.3 , "Corpo del messaggio":

Un server DOVREBBE leggere e inoltrare un corpo del messaggio su qualsiasi richiesta; se il metodo di richiesta non include la semantica definita per un corpo di entità, DOVREBBE DOVREBBE essere ignorato durante la gestione della richiesta.

Cioè, i server dovrebbero sempre leggere qualsiasi corpo di richiesta fornito dalla rete (controllare Content-Length o leggere un corpo grosso, ecc.). Inoltre, i proxy dovrebbero inoltrare qualsiasi organo di richiesta che ricevano. Quindi, se RFC definisce la semantica per il corpo per il metodo dato, il server può effettivamente utilizzare il corpo della richiesta per generare una risposta. Tuttavia, se RFC non definisce la semantica per il corpo, il server dovrebbe ignorarlo.

Questo è in linea con la citazione di Fielding sopra.

La sezione 9.3 , "OTTIENI", descrive la semantica del metodo GET e non menziona gli organismi di richiesta. Pertanto, un server dovrebbe ignorare qualsiasi corpo di richiesta che riceve su una richiesta GET.


La sezione 9.5 , "POST", non menziona anche i corpi di richiesta, quindi questa logica è errata.
CarLuva,

9
@CarLuva La sezione POST dice "Il metodo POST viene utilizzato per richiedere che il server di origine accetti l'entità racchiusa ..." La sezione del corpo dell'entità dice "Il corpo-entità è ottenuto dal corpo del messaggio ..." Pertanto, il La sezione POST menziona il corpo del messaggio, sebbene indirettamente facendo riferimento al corpo dell'entità che viene portato dal corpo del messaggio della richiesta POST.
frederickf,

9

Secondo XMLHttpRequest, non è valido. Dallo standard :

4.5.6 Il send()metodo

client . send([body = null])

Avvia la richiesta. L'argomento facoltativo fornisce il corpo della richiesta. L'argomento viene ignorato se il metodo di richiesta è GETo HEAD.

Genera InvalidStateErrorun'eccezione se uno degli stati non è aperto o il send()flag è impostato.

Il metodo deve eseguire questi passaggi:send(body)

  1. Se lo stato non è aperto , genera InvalidStateErrorun'eccezione.
  2. Se la send()bandiera è impostata, lancia InvalidStateErrorun'eccezione.
  3. Se il metodo di richiesta è GETo HEAD, imposta body su null.
  4. Se body è null, andare al passaggio successivo.

Anche se, non credo che dovrebbe, perché la richiesta GET potrebbe aver bisogno di contenuti di grandi dimensioni.

Quindi, se fai affidamento su XMLHttpRequest di un browser, è probabile che non funzionerà.


1
sottoposto a downgrade a causa del fatto che XMLHttpRequest è un'implementazione. Potrebbe non riflettere le specifiche effettive che dovrebbe implementare.
floum

10
Il downvote sopra è sbagliato, se alcune implementazioni non supportano l'invio di un corpo con un GET, questo potrebbe essere un motivo per non farlo, indipendentemente dalle specifiche. In realtà ho riscontrato questo esatto problema in un prodotto multipiattaforma su cui sto lavorando: solo la piattaforma che utilizza XMLHttpRequest non è riuscita a inviare il get.
pjcard,

8

Se vuoi davvero inviare un corpo JSON / XML cachhable all'applicazione web, l'unico posto ragionevole per mettere i tuoi dati è la stringa di query codificata con RFC4648: codifica Base 64 con URL e nome file Safe Alphabet . Ovviamente potresti semplicemente urlencode JSON e mettere è nel valore del parametro URL, ma Base64 fornisce risultati più piccoli. Tieni presente che esistono restrizioni sulla dimensione dell'URL, vedi Qual è la lunghezza massima di un URL in browser diversi? .

Potresti pensare che il =carattere di riempimento di Base64 potrebbe essere negativo per il valore param dell'URL, tuttavia non sembra - vedi questa discussione: http://mail.python.org/pipermail/python-bugs-list/2007-February/037195.html . Tuttavia non dovresti mettere dati codificati senza nome param perché la stringa codificata con padding verrà interpretata come chiave param con valore vuoto. Vorrei usare qualcosa di simile ?_b64=<encodeddata>.


Penso che sia una pessima idea :) Ma se dovessi fare qualcosa del genere, utilizzerei invece un'intestazione HTTP personalizzata (e assicurerei di rispedire sempre Vary: nella risposta).
Evert

Cattivo o no ma fattibile :) Con i dati nell'intestazione c'è un problema simile con la dimensione dei dati, vedere stackoverflow.com/questions/686217/… . Tuttavia, grazie per aver menzionato l' Varyintestazione, non ero a conoscenza del suo potenziale reale.
Gertas,

6

Non lo consiglierei, va contro le pratiche standard e non offre molto in cambio. Vuoi mantenere il corpo per il contenuto, non per le opzioni.


5

Che dire delle intestazioni codificate in base64 non conformi? "SOMETHINGAPP-PARAMS: sdfSD45fdg45 / come"

Limitazioni di lunghezza hm. Non riesci a fare in modo che la tua gestione POST distingua tra i significati? Se vuoi parametri semplici come l'ordinamento, non vedo perché questo sarebbe un problema. Immagino sia una certezza che ti preoccupi.


È possibile inviare tutti i parametri desiderati con il x-prefisso, eventuali limiti sulla lunghezza delle intestazioni sarebbero interamente un limite arbitrario del server.
Chris Marisic,

4

Sono sconvolto dal fatto che REST come protocollo non supporta OOP e il Getmetodo è una prova. Come soluzione, è possibile serializzare un DTO su JSON e quindi creare una stringa di query. Sul lato server è possibile deserializzare la stringa di query nel DTO.

Dai un'occhiata a:

L'approccio basato sui messaggi può aiutarti a risolvere la restrizione del metodo Get. Sarai in grado di inviare qualsiasi DTO come con il corpo della richiesta

Il framework del servizio Web Nelibur fornisce funzionalità che è possibile utilizzare

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

8
Dovresti semplicemente usare POST. Se nell'URL è presente un nome metodo, stai violando il progetto di riposo fondamentale. Questo è RPC, usa POST.
Annulla il

3
Non penso che sia un grosso problema, abbiamo più problemi durante lo sviluppo con RESTful url (cioè ordini / 1). Quanto a me, qualcosa di sbagliato nel metodo Get, è incompatibile con OOP. E a chi importa come appare l'URL :) Ma con un approccio basato sui messaggi possiamo creare un'interfaccia remota stabile ed è davvero importante. PS non è RPC, è basato sui messaggi
GSerjo

3
Penso che ti manchi l'intero punto di REST. Quando dici, a chi importa che aspetto ha l'URL, beh, REST si preoccupa molto. E perché REST sarebbe compatibile con OOP?
shmish111,

No, non l'ho visto solo un po 'più in là
GSerjo il

4

Ad esempio, funziona con Curl, Apache e PHP.

File 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'

Produzione:

GET
{"the": "body"}

Esperimento divertente! PHP leggerà solo $_POSTquando il corpo viene inviato con una richiesta POST e application/x-www-form-urlencoded. Ciò significa che il corpo viene ignorato in una GETrichiesta. In questo caso: $_GETe $_POSTsono comunque molto fuorvianti a questo punto. Quindi un uso migliorephp://input
Martin Muzatko il

3

IMHO potresti semplicemente inviare il JSONcodificato (ad es. encodeURIComponent) In URL, in questo modo non violerai le HTTPspecifiche e arriverai JSONal server.


28
sì, ma il problema principale è il limite di lunghezza, come possiamo affrontarlo?
Sebas,

2

Hai un elenco di opzioni che sono molto meglio dell'uso di un corpo di richiesta con GET.

Supponiamo che tu abbia categorie ed elementi per ogni categoria. Entrambi devono essere identificati da un id ("catid" / "itemid" per il bene di questo esempio). Si desidera ordinare in base a un altro parametro "sortby" in un "ordine" specifico. Volete passare i parametri per "sortby" e "order":

Puoi:

  1. Utilizzare stringhe di query, ad es example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
  2. Usa mod_rewrite (o simile) per i percorsi: example.com/category/{catid}/item/{itemid}/{sortby}/{order}
  3. Usa le singole intestazioni HTTP che hai passato con la richiesta
  4. Utilizzare un metodo diverso, ad esempio POST, per recuperare una risorsa.

Tutti hanno i loro lati negativi, ma sono molto meglio che usare un GET con un corpo.


0

Anche se uno strumento popolare lo utilizza, come spesso citato in questa pagina, penso che sia ancora una pessima idea, essendo troppo esotico, nonostante non sia proibito dalle specifiche.

Molte infrastrutture intermedie possono semplicemente rifiutare tali richieste.

Con l'esempio, dimenticare utilizzando alcuni dei CDN disponibili di fronte al vostro sito web, come questo uno :

Se una GETrichiesta del visualizzatore include un corpo, CloudFront restituisce al visualizzatore un codice di stato HTTP 403 (vietato).

E sì, le librerie client potrebbero anche non supportare l'emissione di tali richieste, come riportato in questo commento .


0

Sto usando RestTemplate del framework Spring nel mio programma client e, sul lato server, ho definito una richiesta GET con un corpo Json. Il mio scopo principale è lo stesso del tuo: quando la richiesta ha numerosi parametri, inserirli nel corpo sembra più ordinato che inserirli nella stringa URI prolungata. Sì?

Ma, purtroppo, non funziona! Il lato server ha generato la seguente eccezione:

org.springframework.http.converter.HttpMessageNotReadableException: corpo della richiesta richiesto mancante ...

Ma sono abbastanza sicuro che il corpo del messaggio sia correttamente fornito dal mio codice client, quindi cosa c'è che non va?

Ho rintracciato nel metodo RestTemplate.exchange () e ho trovato quanto segue:

// 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();
        }
        ...
    }
}

Si noti che nel metodo executeInternal (), l'argomento di input 'bufferedOutput' contiene il corpo del messaggio fornito dal mio codice. L'ho visto attraverso il debugger.

Tuttavia, a causa del preparConnection (), getDoOutput () in executeInternal () restituisce sempre false che, a sua volta, rende bufferedOutput completamente ignorato! Non viene copiato nel flusso di output.

Di conseguenza, il mio programma server non ha ricevuto il corpo del messaggio e ha generato tale eccezione.

Questo è un esempio del RestTemplate del framework Spring. Il punto è che, anche se il corpo del messaggio non è più proibito dalle specifiche HTTP, alcune librerie o framework client o server potrebbero comunque essere conformi alle specifiche precedenti e rifiutare il corpo del messaggio dalla richiesta GET.


Non stai leggendo le specifiche o i commenti qui correttamente. Client e server cadere il corpo della richiesta è in specifica. Non utilizzare gli organismi di richiesta GET.
Evert

@Evert Non ho letto correttamente i commenti o no? :) Se scorri fino alla risposta di Paul Morgan (la risposta più in alto) e leggi attentamente i commenti, troverai questo: "RFC2616 indicato come" Specifica HTTP / 1.1 "è ora obsoleto. Nel 2014 è stato sostituito da Gli RFC 7230-7237. La citazione "il corpo del messaggio DOVREBBE essere ignorato durante la gestione della richiesta" è stata eliminata. Ora è solo "La richiesta del frame del messaggio è indipendente dalla semantica del metodo, anche se il metodo non definisce alcun uso per un corpo del messaggio ... "
Zhou

@Evert Inoltre, stavo usando l'utilità di test REST "rassicurato" per testare il mio backend Spring-boot. Sia il resto sicuro che il server Spring-boot hanno mantenuto il corpo Json per la richiesta GET! Solo RestTemplate di Sping-framework lascia cadere il corpo dalle richieste GET, quindi Spring-boot, rest-rassured e RestTemplate, che è / sono sbagliato?
Zhou

@Evert Last ma not lease, non ho esortato le persone a usare body nelle richieste GET, al contrario, stavo suggerendo di NON farlo analizzando il codice sorgente del RestTemplate di Sping-framework, quindi perché hai votato risposta?
Zhou

Non ho votato in negativo la tua risposta. Sto solo chiarendo che qualsiasi implementazione HTTP che elimina la richiesta GET è nelle specifiche.
Evento il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.