2011-02-22 12 views
45

Sto scrivendo un'API REST per un servizio che accetterà i dati forniti dall'utente. Vorrei mantenere tutte le operazioni completamente asincrone, questo include PUT, POST, DELETE e forse anche richieste GET. La mia idea è di ricevere la richiesta, elaborarla abbastanza per garantire che sia una richiesta valida e quindi passare una risposta accettata HTTP 202 insieme a un url dove i dati saranno eventualmente disponibili e un token in modo che le richieste successive possano essere abbinate ai dati elaborati . Se la richiesta non è valida, invierò un HTTP 400.Utilizzare lo stato HTTP 202 per le operazioni asincrone

Il cliente sarà quindi responsabile di controllare l'URL che ho fornito in futuro e passare il token. Se i dati sono disponibili, restituisco un normale 200 o 201 ma se sto ancora elaborando la richiesta invierò un altro 202 che indica che l'elaborazione non è stata completata. In caso di errori nell'elaborazione dei dati, invierò lo stato 4xx o 5xx se necessario.

Il motivo per cui desidero farlo è che posso scaricare tutte le richieste valide in un pool di richieste e fare in modo che i dipendenti estraggono dalla coda ed elaborino le richieste non appena sono disponibili. Dato che non conosco le dimensioni del pool o il numero di lavoratori disponibili, non posso essere certo di poter ottenere richieste abbastanza veloci da soddisfare il limite di 30 secondi di Google App Engine.

La mia domanda è: sto pervertendo REST elaborando le richieste in questo modo? I browser, ad esempio, sembrano richiedere risposte immediate alle richieste. Per le mie pagine HTML ho intenzione di rispondere con la pagina strutturata e quindi utilizzare AJAX per elaborare le richieste di dati.

Sono principalmente interessato a qualsiasi opinione o esperienza nell'elaborazione dei dati utilizzando REST in questo modo.

+0

Ti aspetti browser per utilizzare questo direttamente? Perché questa soluzione sembra soddisfacente per un'API (vedi la risposta di @systempuntoout), ma ovviamente non funzionerà per un browser web. –

+0

Ho intenzione di provare e limitare i browser alle operazioni GET con le query più probabili conservate in memoria (ad esempio memcached). Eventuali query a più lungo termine verranno probabilmente eseguite tramite AJAX utilizzando il polling con un indicatore di avanzamento visualizzato (ad esempio il filtro di set di risultati di grandi dimensioni). PUT e POST saranno probabilmente simili al caricamento di video di youtube dove fornisco all'utente un messaggio standard "il tuo media è in elaborazione" finché il server non ha completato l'attività. –

+0

Alcune risorse per restapi http://stackoverflow.com/questions/14124056/rest-api-202-versus-204/27766943#27766943 –

risposta

29

Penso che la soluzione va bene, il Http status 202 è la proper response da utilizzare in questo caso specifico che indica che la richiesta è stata accettata per l'elaborazione, ma l'elaborazione non è stata completata.

Che cosa cambierei leggermente nel flusso di lavoro sono le Http status delle richieste successive.

Come hai detto, lo 202 response deve restituire un Location header specificando l'URL che il client deve utilizzare per monitorare lo stato della sua richiesta precedente.
chiamata a questo Check-the-status-of-my-processo URL, invece di restituire un 202 in caso di processo in corso, vorrei tornare:

  1. 200 OK quando il processo di richiesta è ancora in sospeso. La risposta dovrebbe descrivere lo stato in sospeso del processo.
  2. 201 Created quando l'elaborazione è stata completata. La risposta in caso di GET/PUT/POST dovrebbe contenere la Posizione alla risorsa richiesta/creata/aggiornata.
+1

Sono d'accordo con le risposte di stato. Sembra un po 'imbarazzante inviare il 200 OK mentre sto ancora elaborando, dal momento che suggerisce "La richiesta è riuscita". Tuttavia 202 suggerisce anche che la richiesta è stata accettata, il che non è il caso quando sto controllando i progressi. Non esiste uno status preciso per descrivere ciò che voglio in modo che 200 possa essere considerato "finora così buono". –

+12

Sono d'accordo con questo, ma non penso che sia "201" o "202" abbia senso per le richieste successive. I codici di stato hanno lo scopo di indicare lo stato della richiesta/risposta - _non_ la risorsa. Rimani con '200' sulle richieste di follow-up, e usa la rappresentazione per rappresentare lo stato della risorsa. –

+0

c'è qualche codice di esempio? – plzdontkillme

21

Aggiungendo i miei due centesimi a una vecchia domanda. La mia idea è simile ai suggerimenti di systempuntoout e Avi Flax.

Accetto che una risposta HTTP 202 sia appropriata per la richiesta iniziale con un reindirizzamento a un'altra risorsa tramite un'intestazione Location.

Penso che l'URL Location dovrebbe probabilmente includere il token a cui si fa riferimento per conformarsi alle aspettative comuni di un reindirizzamento Location. Ad esempio Location: /queue?token={unique_token} o Location: /task/{unique_token}.

Penso anche che la risorsa utilizzata per controllare lo stato del processo dovrebbe restituire una risposta HTTP 200 quando l'azione di "verifica dello stato" ha successo (non un HTTP 202 causa che implica la richiesta di corrente è stato "accettato").

Tuttavia, penso che quando si crea la nuova entità "verifica dello stato" dovrebbe restituire una risposta HTTP 303 (See Other) con un colpo di testa Location per la nuova entità una volta che è stato creato. Questo è più appropriato dell'invio di un HTTP 201 perché non è stato creato nulla a causa della richiesta GET appena eseguita per controllare lo stato.

Penso anche che la risorsa utilizzata per controllare lo stato dovrebbe restituire i codici di errore in modo appropriato. Ogni volta che "controllare lo stato" viene eseguito correttamente, deve essere restituito un codice di successo appropriato. Gli errori possono essere gestiti a livello di applicazione (controllando il corpo della risposta).

+0

Mi piace l'idea di utilizzare un reindirizzamento 303 per fare in modo che il client completi la richiesta su un altro URL. Guardando la pagina di wikipedia che hai linkato, descrivi anche il suo uso esattamente per il mio scopo originale. Grazie per la risposta. –

6

Questa è una domanda molto vecchia, ma mi piacerebbe offrire una visione leggermente diversa di questo, che non pretendo di essere corretta, solo la mia opinione.

Dal punto di vista del cliente

Partiamo subito con la richiesta HTTP iniziale. Prima di tutto, la richiesta dovrebbe essere POST. Stai inviando un messaggio al server per creare una risorsa. GET e PUT non sono validi in questo caso perché:

  • Un GET non è valido in questo contesto perché un GET ha lo scopo di ottenere la risorsa in una posizione specifica
  • Un PUT non è valida perché non siete creando la richiesta, stai chiedendo al server di creare la richiesta.

Dal punto di vista del servizio

Così ora si sta inviando un POST al server per elaborare una richiesta. L'assistente ha davvero 3 valori restituiti possibili (senza contare gli errori 4xx e 5xx):

  • "201 Creato" indica che il servizio ha ottenuto la richiesta ed è stato in grado di elaborare immediatamente, o entro un periodo di tempo accettabile. Questo periodo di tempo è completamente in linea con la progettazione del servizio. Spetta allo sviluppatore del servizio definirlo.
  • "202 Accettato" indica che il servizio ha ricevuto la richiesta e la sta elaborando. Questo è usato quando il servizio sa che ci vorrà del tempo. L'altra prospettiva è che se il servizio fa affidamento su qualsiasi altra operazione asincrona che non ha modo di determinare il risultato, allora dovrebbe restituire la risposta "202 Accettato". Infine, alcuni progettisti di servizi possono semplicemente restituire sempre "202 Accettato" indipendentemente dalla velocità con cui può essere eseguito.
  • In alcuni casi, si otterrebbe un "302 trovato". Questo di solito è quando il servizio può identificare una richiesta come generare una risorsa che esiste già (ed è ancora valida e non in uno stato di errore) e che riutilizzare una risorsa esistente è accettabile. Non tutti i servizi funzionano in questo modo: la pubblicazione di un commento su un thread dovrebbe sempre creare nuove risorse. Altri servizi: pubblicare una serie di criteri per ottenere un elenco di medici produce la stessa lista di medici. Se queste informazioni possono essere riutilizzate, quindi riutilizzarle.
  • Con tutte queste risposte, l'intestazione HTTP "Posizione" viene restituita al client contenente la posizione in cui è possibile trovare la risorsa.Questo è importante e dove alcune persone tendono a divergere nell'approccio, come vedremo più avanti. Se la risorsa può essere riutilizzata con altre richieste, la "Posizione" dovrebbe essere generata in modo che le stesse richieste generino sempre gli stessi URL. Ciò fornisce una buona dose di cache e riutilizzo.

Quando il servizio ha completato correttamente la richiesta, creerà la risorsa nella posizione che è stata restituita al client.

Ora è qui che comincio a vedere le cose un po 'diverse dalla risposta sopra.

Se il servizio non riesce a completare la richiesta, dovrebbe comunque creare una risorsa nella posizione che è stata restituita al client. Questa risorsa dovrebbe indicare il motivo dell'errore. È molto più flessibile avere una risorsa che fornisca informazioni di errore piuttosto che provare a inserirla nel protocollo HTTP.

Se il servizio riceve la richiesta di questa risorsa prima che sia completata, deve restituire "404 non trovato". Il motivo per cui credo che dovrebbe essere un "404 non trovato" è perché in realtà non esiste. Le specifiche HTTP non dicono che "404 Not Found" può essere usato solo per quando una risorsa non esisterà mai, solo che ora non esiste. Secondo me, questo tipo di risposta a un flusso di polling asincrono è completamente corretto.

C'è anche lo scenario di quando una risorsa dovrebbe essere lì solo per un tempo fisso. Ad esempio, potrebbe trattarsi di dati basati su una fonte che viene aggiornata ogni notte. Ciò che dovrebbe accadere in questi casi è che la risorsa debba essere rimossa, ma al servizio dovrebbe essere fornito un indicatore che possa sapere per restituire un codice di stato "410 Gone". Questo fondamentalmente sta dicendo al cliente che la risorsa era qui, ma non è più disponibile (es: potrebbe essere scaduta). L'azione tipica da parte del cliente sarebbe quella di inviare nuovamente la richiesta.

Dal punto di vista del cliente di nuovo

Quando il client ottiene la risposta per esso è POST iniziale, si ottiene il "Location" e fa la richiesta al servizio utilizzando l'URL utilizzando un GET (di nuovo, non POST). Il servizio risponderà generalmente con questi valori:

  • "200 OK" indica che la richiesta è stata completata. Il risultato della richiesta viene restituito nel corpo del contenuto, fornendo il contenuto nel formato definito dall'intestazione Accetta HTTP.
  • "404 Not Found" indica al client che la richiesta non è stata ancora completata, la risorsa non è ancora disponibile e, in questo caso, dovrebbe riprovare in un secondo momento.
  • "410 Gone" verrebbe restituito nei casi in cui il client possa tentare di ottenere la risorsa dopo un lungo periodo di tempo e non ci sia più. In questo caso, è sufficiente inviare nuovamente la query originale

L'unica cosa che deve essere sottolineata è che la risorsa che viene restituita è generalmente in un formato che può definire le risposte di successo e di errore. Il client dovrebbe essere in grado di determinare da questa risorsa se c'è stato un errore, di cosa si trattava ed essere in grado di rispondere di conseguenza.

Inoltre, lo sviluppatore del servizio può farlo in modo che il servizio scada e cancelli la risorsa di errore dopo un breve periodo di tempo.

Quindi questa è la mia opinione su questa domanda. È molto tardi per la festa, ma spero che i futuri lettori possano vedere una visione leggermente diversa rispetto a una domanda comune.

+3

Il problema con 404 è che è memorizzabile nella cache. (Vedi http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-25#section-6.1). Riprovare a 404 finché non riesce probabilmente non è un buon modello da usare e sembra molto non standard. Gli errori 4xx sono in particolare errori del client. Gli errori 4xx implicano che il cliente ha commesso un errore o non è riuscito a passare alcune informazioni necessarie necessarie per accedere a una risorsa. Nell'uso normale, ottenere un'intestazione Location che si risolve in un 404 è un bug. (Ad es. Una condizione di competizione o un problema di coerenza del database.) – ngreen

+2

Buoni punti. Il problema di Cacheable può essere risolto dalle intestazioni HTTP del controllo di memorizzazione nella cache. Per quanto riguarda il secondo punto, questo è un buon punto. È, tecnicamente, non un uso non corretto di 404, ma fai sorgere una preoccupazione valida. –

+1

Si potrebbe considerare l'utilizzo dell'intestazione Content-Location per il recupero di uno stato dell'operazione. Altrimenti sono d'accordo con Dino. Ispirazione per la Content-Location può essere trovata qui su Microsoft Azure: https://docs.microsoft.com/en-us/rest/api/hdinsight/asynchronous-operations--202-accepted-and-location-header- –

1

FWIW, Microsoft Flow utilizza uno schema come questo.
Prima chiamata restituisce 202 w/Intestazione posizione. Le chiamate di follow-up restituiscono: 1. Se l'elaborazione è ancora in corso -> 202 w/un'intestazione di posizione. L'intestazione del loc può essere diversa, che fornisce un modo per passare lo stato tra le chiamate (e potenzialmente rendere il server stateless!). 2. Se fatto -> 200.

la scheda a: https://github.com/jeffhollan/LogicAppsAsyncResponseSample

Problemi correlati