POST HTTP con parametri di query URL: buona idea o no? [chiuso]


451

Sto progettando un'API per andare su HTTP e mi chiedo se usare il comando HTTP POST, ma con solo i parametri di query URL e nessun corpo di richiesta, sia un buon modo di procedere.

considerazioni:

  • "Good Web design" richiede che le azioni non idempotenti vengano inviate tramite POST. Questa è un'azione non idempotente.
  • È più semplice sviluppare ed eseguire il debug di questa app quando i parametri della richiesta sono presenti nell'URL.
  • L'API non è destinata ad un uso diffuso.
  • Sembra che fare una richiesta POST senza body richiederà un po 'più di lavoro, ad esempio Content-Length: 0un'intestazione deve essere aggiunta esplicitamente.
  • Mi sembra anche che un POST senza body sia un po 'contrario alle aspettative della maggior parte dei framework HTTP e degli sviluppatori.

Ci sono più insidie ​​o vantaggi nell'invio di parametri su una richiesta POST tramite la query URL anziché il corpo della richiesta?

Modifica: il motivo per cui questo è in considerazione è che le operazioni non sono idempotenti e hanno effetti collaterali diversi dal recupero. Vedi le specifiche HTTP :

In particolare, è stata stabilita la convenzione che i metodi GET e HEAD NON DOVREBBERO avere il significato di intraprendere un'azione diversa dal recupero. Questi metodi dovrebbero essere considerati "sicuri". Ciò consente agli interpreti utenti di rappresentare altri metodi, come POST, PUT e DELETE, in modo speciale, in modo che l'utente venga a conoscenza del fatto che viene richiesta un'azione potenzialmente non sicura.

...

I metodi possono anche avere la proprietà di "idempotenza" in quanto (a parte errori o problemi di scadenza), gli effetti collaterali di richieste identiche N> 0 sono gli stessi di una singola richiesta. I metodi GET, HEAD, PUT e DELETE condividono questa proprietà. Inoltre, i metodi OPTIONS e TRACE NON DOVREBBERO avere effetti collaterali, e quindi sono intrinsecamente idempotenti.


11
Perché usare il POST se non hai intenzione di fornire dati nel corpo?
Sunny Milenov

114
Perché l'operazione non è idempotente.
Steven Huwig

20
@Jared, nota che la parola "REST" non appare in questa domanda da 2,5 anni fa. :) Le specifiche HTTP sull'idempotenza si applicano indipendentemente dall'architettura del mese per i servizi Web. Fortunatamente, il sistema per cui questa API è stata progettata per il proxy è stato reso comunque obsoleto.
Steven Huwig,

5
Poiché i registri del server non registrano i parametri POST, ma registrano le stringhe di query. È molto più semplice eseguire la serie di richieste senza strumentarla nel browser e quindi guardare il traceback, piuttosto che fare clic su di esse. Inoltre, l'API non era da browser a server, ma piuttosto da server a server. Ancora più importante, l'intera faccenda è stata comunque inscatolata. :)
Steven Huwig,

13
Per chiunque non sappia cosa significa idempotente: | restapitutorial.com/lessons/idempotency.html
Christopher Grigg,

Risposte:


259

Se la tua azione non è idempotente, DEVI usare POST. In caso contrario, stai solo chiedendo problemi lungo la linea. GET, PUTE DELETEmetodi sono necessari per essere idempotente. Immagina cosa accadrebbe nella tua applicazione se il client stesse pre-recuperando ogni possibile GETrichiesta per il tuo servizio - se ciò causasse effetti collaterali visibili al client, allora qualcosa non va.

Concordo sul fatto che inviare a POSTcon una stringa di query ma senza un corpo sembra strano, ma penso che possa essere appropriato in alcune situazioni.

Pensa alla parte della query di un URL come un comando alla risorsa per limitare l'ambito della richiesta corrente. In genere, le stringhe di query vengono utilizzate per ordinare o filtrare una GETrichiesta (come ?page=1&sort=title), ma suppongo che abbia senso POSTlimitare anche l'ambito (forse come ?action=delete&id=5).


4
Ho scelto questa risposta per questo caso particolare, ma penso che l'argomento di R. Bemrose sia convincente per le API pubbliche.
Steven Huwig,

4
Non credo che la sua risposta sia assolutamente corretta. Se si conoscono i parametri URL per il post del modulo quando la pagina HTML viene inviata al client, è possibile applicare tali parametri URL all'attributo action del modulo, altrimenti JavaScript può impostare i parametri URL quando viene inviato il modulo.
Don McCaughey,

3
che ne dici di un post di un file XML in un URL con parametri di query? è possibile?
OpenCoderX

3
Un altro esempio: i dati della richiesta potrebbero essere nell'entità http, mentre il formato richiesto della risposta viene passato nel parametro query ( /action?response_format=json)
rds

4
+1 ho imparato qualcosa oggi. Elimina ha un tecnicismo per essere idempotente. Se l'oggetto viene effettivamente cancellato, otterrai un 404 non trovato, quindi il server avrà lo stesso stato ma la risposta sarà diversa. Guarda l'immagine della mucca: restapitutorial.com/lessons/idempotency.html
JPK

131

Tutti hanno ragione: attenersi al POST per richieste non idempotenti.

Che ne dici di usare sia una stringa di query URI sia il contenuto della richiesta? Bene, è un HTTP valido (vedi nota 1), quindi perché no ?!

È anche perfettamente logico: gli URL, inclusa la parte della stringa di query, servono per individuare le risorse. Considerando che i verbi del metodo HTTP (POST - e il suo contenuto di richiesta opzionale) servono per specificare le azioni o cosa fare con le risorse. Quelle dovrebbero essere preoccupazioni ortogonali. (Ma non sono meravigliosamente preoccupazioni ortogonali per il caso speciale di ContentType = application / x-www-form-urlencoded, vedere la nota 2 di seguito.)

Nota 1: la specifica HTTP (1.1) non afferma che i parametri e il contenuto della query si escludono a vicenda per un server HTTP che accetta richieste POST o PUT. Quindi qualsiasi server è libero di accettare entrambi. Vale a dire se si scrive sul server non c'è nulla che ti impedisca di scegliere di accettare entrambi (tranne forse un framework non flessibile). In generale, il server può interpretare le stringhe di query in base alle regole che desidera. Può persino interpretarli con una logica condizionale che fa riferimento anche ad altre intestazioni come Content-Type, che porta alla Nota 2:

Nota 2: se un browser Web è il modo principale in cui le persone accedono alla tua applicazione Web e application / x-www-form-urlencoded è il Tipo di contenuto che pubblicano, allora dovresti seguire le regole per quel Tipo di contenuto. E le regole per application / x-www-form-urlencoded sono molto più specifiche (e francamente, inusuali): in questo caso è necessario interpretare l'URI come un insieme di parametri e non come una posizione delle risorse. [Questo è lo stesso punto di utilità sollevato da Powerlord; che potrebbe essere difficile utilizzare i moduli Web per pubblicare il contenuto sul server. Ho solo spiegato un po 'diversamente.]

Nota 3: a cosa servono originariamente le stringhe di query? RFC 3986 definisce le stringhe di query HTTP come una parte URI che funziona come un modo non gerarchico di localizzazione di una risorsa.

Nel caso in cui i lettori che fanno questa domanda desiderano porre ciò che è buona architettura RESTful: il modello di architettura RESTful non richiede schemi URI per funzionare in un modo specifico. L'architettura RESTful si occupa di altre proprietà del sistema, come la cache delle risorse, la progettazione delle risorse stesse (comportamento, capacità e rappresentazioni) e se l'idempotenza è soddisfatta. O in altre parole, ottenere un design altamente compatibile con il protocollo HTTP e il suo set di verbi del metodo HTTP. :-) (In altre parole, l'architettura RESTful non è molto prescrittiva su come si trovano le risorse .)

Nota finale: a volte i parametri della query vengono utilizzati per altre cose, che non localizzano risorse né codificano il contenuto. Hai mai visto un parametro di query come 'PUT = true' o 'POST = true'? Queste sono soluzioni alternative per i browser che non ti consentono di utilizzare i metodi PUT e POST. Mentre tali parametri sono visti come parte della stringa di query dell'URL (sul filo), sostengo che non fanno parte della query dell'URL nello spirito .


66

Vuoi ragioni? Eccone uno:

Non è possibile utilizzare un modulo Web per inviare una richiesta a una pagina che utilizza un mix di GET e POST. Se si imposta il metodo del modulo su GET, tutti i parametri si trovano nella stringa della query. Se si imposta il metodo del modulo su POST, tutti i parametri si trovano nel corpo della richiesta.

Fonte: HTML 4.01 standard, sezione 17.13 Invio modulo


10
Questo è un argomento decente, ma penso che le implementazioni Javascript del browser moderno ne facciano un punto controverso. Ci penserò comunque: è avvincente in un modo a prova di futuro. Solo perché non sto usando un modulo per questo ora non significa che non lo vorrò più tardi.
Steven Huwig

9
Mescolare GET con POST è solo una pessima idea: interrompere terribilmente HTTP e senza una buona ragione.
aehlke,

6
Quel frammento non appare nella pagina a cui ti sei collegato
Gareth,

40
Giusto, ma l'attributo del metodo definisce semplicemente come il "set di dati del modulo" è incluso nella richiesta. Quando methodè POST, non si fa menzione della modifica dell'URI nei moduli action. E ovviamente qualsiasi URI può già contenere una parte della stringa di query.
Gareth,

16
@Powerlord Questo è semplicemente sbagliato. Prova a impostare un modulo su POST con un'azione ad es. /Books?bookCode=1234. Il web server otterrà VAR dai moduli POST e una stringa di query.
Jez,

9

Da un punto di vista programmatico, per il cliente è impacchettare i parametri e aggiungerli all'URL e condurre un POST contro un GET. Sul lato server, sta valutando i parametri in entrata dalla stringa di query anziché dai byte postati. Fondamentalmente, è un lavaggio.

Dove potrebbero esserci vantaggi / svantaggi potrebbe essere il modo in cui piattaforme client specifiche funzionano con le routine POST e GET nel loro stack di rete, nonché in che modo il server Web gestisce tali richieste. A seconda dell'implementazione, un approccio può essere più efficiente dell'altro. Sapere che guiderebbe la tua decisione qui.

Tuttavia, dal punto di vista di un programmatore, preferisco consentire un POST con tutti i parametri nel corpo o un GET con tutti i parametri sull'URL e ignorare esplicitamente i parametri dell'URL con qualsiasi richiesta POST. Evita la confusione.


8

Penso che potrebbe essere ancora abbastanza RESTful avere argomenti di query che identificano la risorsa sull'URL mantenendo il payload del contenuto limitato al corpo POST. Ciò sembrerebbe separare le considerazioni di "Che cosa sto inviando?" contro "A chi lo sto inviando?".


5
La domanda non riguardava REST.
Steven Huwig,

3
@ user359996 Non tutte le API HTTP sono RESTful. In effetti, la maggior parte delle API che sostengono che in realtà non lo sono. Inoltre, fatto divertente, REST non è neanche solo HTTP.
Alec Mev,

4

Il campo REST ha alcuni principi guida che possiamo usare per standardizzare il modo in cui usiamo i verbi HTTP. Questo è utile quando si creano API RESTful mentre si sta facendo.

In breve: GET dovrebbe essere di sola lettura, cioè non avere alcun effetto sullo stato del server. POST viene utilizzato per creare una risorsa sul server. PUT viene utilizzato per aggiornare o creare una risorsa. DELETE viene utilizzato per eliminare una risorsa.

In altre parole, se l'azione dell'API modifica lo stato del server, REST ci consiglia di utilizzare POST / PUT / DELETE, ma non GET.

I programmi utente di solito comprendono che eseguire più POST è un male e lo avvertiranno, perché l'intenzione di POST è di modificare lo stato del server (ad es. Pagare la merce alla cassa), e probabilmente non vorrai farlo due volte!

Confronta con un GET che puoi fare spesso come preferisci (idempotente).


13
Il campo REST dice che dovresti usare HTTP come definito nelle specifiche HTTP. cioè RFC2616 Niente di più, niente di meno.
Darrel Miller,

1
@Darrel Riferendosi a ibm.com/developerworks/webservices/library/ws-restful : REST chiede agli sviluppatori di usare i metodi HTTP esplicitamente e in modo coerente con la definizione del protocollo. Questo principio di progettazione REST di base stabilisce un mapping uno a uno tra le operazioni di creazione, lettura, aggiornamento ed eliminazione (CRUD) e metodi HTTP. Secondo questo mapping: Per creare una risorsa sul server, utilizzare POST. Per recuperare una risorsa, utilizzare GET. Per modificare lo stato di una risorsa o per aggiornarla, utilizzare PUT. Per rimuovere o eliminare una risorsa, utilizzare CANC.
salpa il

5
Scusa ma è semplicemente sbagliato. REST richiede la conformità a un'interfaccia uniforme. Se si utilizza HTTP, quell'interfaccia uniforme è definita in parte da RFC 2616. In tale specifica, non esiste un mapping uno a uno tra i metodi di creazione, lettura, aggiornamento ed eliminazione e HTTP.
Darrel Miller,

3
OTTIENI e ELIMINA la mappa abbastanza bene da leggere ed eliminare in CRUD, ma l'utilizzo di PUT / POST per l'aggiornamento e la creazione non è così semplice. Vedere stackoverflow.com/questions/630453/put-vs-post-in-rest
dcstraw

5
Guardando indietro a questo 6 anni dopo, e dato che la domanda è stata vista ~ 100k volte, ritengo che valga la pena inserire un piccolo aggiornamento. Darrel è corretto secondo la definizione di REST di Fielding ( ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm ) - non si fa menzione della mappatura dei verbi HTTP su CRUD. Il consiglio dello sviluppatore IBM (link nel commento sopra) riflette la pratica comune nell'implementazione dell'API RESTful, non la definizione di REST di Fielding.
salpa il

-13

Sono d'accordo - probabilmente è più sicuro utilizzare una richiesta GET se stai semplicemente passando i dati nell'URL e non nel corpo. Vedi questa domanda simile per alcune viste aggiuntive sull'intero concetto POST + GET.


17
Se l'operazione ha effetti collaterali, allora non è certamente 'più sicuro' usare il metodo GET perché il browser presume che tutti i GET siano idempotenti.
dcstraw,

I motori di ricerca lo convertono anche in un incubo, poiché Google "farà clic" in modo sicuro su tutti i collegamenti con la richiesta GET, ma ometterà tutto il resto. Non è così sicuro lasciare un servizio che un crawler innocente può cancellare accidentalmente il database.
Alejandro,
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.