Codice di stato HTTP per "Elaborazione in corso"

38

Sto costruendo un'API RESTful che supporta l'accodamento di attività a esecuzione prolungata per un'eventuale gestione.

Il tipico flusso di lavoro per questa API sarebbe:

  1. L'utente compila il modulo
  2. Il cliente pubblica i dati nell'API
  3. L'API restituisce 202 Accettato
  4. Il client reindirizza l'utente a un URL univoco per quella richiesta ( /results/{request_id} )
  5. ~ fine ~
  6. Il client visita nuovamente l'URL e visualizza i risultati su quella pagina.

Il mio problema è nel passaggio 6. Ogni volta che un utente visita la pagina, inoltro una richiesta alla mia API ( GET /api/results/{request_id} ). Idealmente, l'attività sarà già completata, e restituirei 200 OK con i risultati del loro compito.

Ma gli utenti sono invadenti e mi aspetto molti aggiornamenti eccessivi quando il risultato non è ancora terminato.

Qual è la mia migliore opzione per un codice di stato per indicare che:

  • questa richiesta esiste,
  • non è ancora finito,
  • ma non ha fallito.

Non mi aspetto un singolo codice per comunicare tutto ciò, ma mi piacerebbe qualcosa che mi permetta di passare i metadati invece di aspettare che il client si aspetti il contenuto.

Potrebbe avere senso restituire un 202, dato che non avrebbe alcun altro significato qui: è una richiesta GET , quindi nulla può essere "accettato". Sarebbe una scelta ragionevole?

L'ovvia alternativa a tutto questo - che funziona, ma sconfigge uno scopo dei codici di stato - sarebbe di includere sempre i metadati:

200 OK

{
    status: "complete",
    data: {
        foo: "123"
    }
}

... o ...

200 OK

{
    status: "pending"
}

Quindi lato client, vorrei (sospirare) switch su response.data.status per determinare se la richiesta è stata completata.

È questo che dovrei fare? O c'è un'alternativa migliore? Mi sembra così Web 1.0 per me.

    
posta Matthew Haugen 19.04.2016 - 19:46
fonte

4 risposte

40

HTTP 202 accettato (HTTP / 1.1)

Stai cercando lo stato HTTP 202 Accepted . Vedi RFC 2616 :

The request has been accepted for processing, but the processing has not been completed.

Elaborazione HTTP 102 (WebDAV)

RFC 2518 suggerisce di utilizzare HTTP 102 Processing :

The 102 (Processing) status code is an interim response used to inform the client that the server has accepted the complete request, but has not yet completed it.

ma ha un avvertimento:

The server MUST send a final response after the request has been completed.

Non sono sicuro di come interpretare l'ultima frase. Il server dovrebbe evitare di inviare qualcosa durante l'elaborazione e rispondere solo dopo al completamento? O costringe solo a terminare la risposta solo quando l'elaborazione termina? Questo potrebbe essere utile se vuoi segnalare i progressi. Invia HTTP 102 e svuota la risposta byte per byte (o riga per riga).

Ad esempio, per un processo lungo ma lineare, puoi inviare cento punti, sciacquando ogni carattere. Se il lato client (come un'applicazione JavaScript) sa che dovrebbe aspettarsi esattamente 100 caratteri, può abbinarlo con una barra di avanzamento da mostrare all'utente.

Un altro esempio riguarda un processo che consiste in diversi passaggi non lineari. Dopo ogni passaggio, puoi svuotare un messaggio di log che verrebbe visualizzato all'utente, in modo che l'utente finale possa sapere come sta andando il processo.

Problemi con lo spurgo progressivo

Nota che mentre questa tecnica ha i suoi meriti, non la consiglierei . Uno dei motivi è che costringe la connessione a rimanere aperta, il che potrebbe danneggiare in termini di disponibilità del servizio e non si adatta bene.

Un approccio migliore consiste nel rispondere con HTTP 202 Accepted e consentire all'utente di tornare in un secondo momento per determinare se l'elaborazione è terminata (ad esempio chiamando ripetutamente un dato URI come /process/result che risponderebbe con HTTP 404 Non trovato o Conflitto HTTP 409 fino a quando il processo termina e il risultato è pronto), o avvisare l'utente quando l'elaborazione viene eseguita se è possibile richiamare il client, ad esempio, tramite un servizio di accodamento messaggi ( esempio ) o WebSockets.

Esempio pratico

Immagina un servizio Web che converte i video. Il punto di ingresso è:

POST /video/convert

che prende un file video dalla richiesta HTTP e fa un po 'di magia con esso. Immaginiamo che la magia abbia un uso intensivo della CPU, quindi non può essere eseguita in tempo reale durante il trasferimento della richiesta. Ciò significa che una volta trasferito il file, il server risponderà con una HTTP 202 Accepted con alcuni contenuti JSON, che significa "Sì, ho ricevuto il tuo video e ci sto lavorando; sarà pronto da qualche parte in futuro e sarà disponibile attraverso l'ID 123. "

Il client ha la possibilità di iscriversi a una coda di messaggi per essere avvisati al termine dell'elaborazione. Al termine, il client può scaricare il video elaborato andando a:

GET /video/download/123

che porta a HTTP 200 .

Cosa succede se il client interroga questo URI prima di ricevere la notifica? Bene, il server risponderà con HTTP 404 poiché, in effetti, il video non esiste ancora. Potrebbe essere attualmente preparato. Potrebbe non essere mai stato richiesto. Potrebbe esistere un po 'di tempo in passato e essere rimosso in seguito. Tutto ciò che conta è che il video risultante non sia disponibile.

Ora, che cosa succede se al cliente importa non solo il video finale, ma anche il progresso (che sarebbe ancora più importante se non ci sono servizi di code messaggi o meccanismi simili)?

In questo caso, puoi usare un altro endpoint:

GET /video/status/123

che risulterebbe in una risposta simile a questa:

HTTP 200
{
    "id": 123,
    "status": "queued",
    "priority": 2,
    "progress-percent": 0,
    "submitted-utc-time": "2016-04-19T13:59:22"
}

Facendo ripetutamente la richiesta mostrerai i progressi finché non sarà:

HTTP 200
{
    "id": 123,
    "status": "done",
    "progress-percent": 100,
    "submitted-utc-time": "2016-04-19T13:59:22"
}

È fondamentale fare la differenza tra questi tre tipi di richieste:

  • POST /video/convert mette in coda un'attività. Dovrebbe essere chiamato una sola volta: chiamandolo di nuovo si accoderebbe un'ulteriore attività.
  • GET /video/download/123 riguarda il risultato dell'operazione: la risorsa è il video. L'elaborazione, ovvero ciò che è accaduto sotto il cofano per preparare il risultato effettivo prima della richiesta e indipendentemente dalla richiesta, è irrilevante qui. Può essere chiamato una o più volte.
  • GET /video/status/123 riguarda l'elaborazione di per sé . Non fa la coda nulla. Non interessa il video risultante. La risorsa è l'elaborazione stessa. Può essere chiamato una o più volte.
risposta data 19.04.2016 - 20:07
fonte
3

The obvious alternative to all this -- which functions, but defeats one purpose of status codes -- would be to always include the metadata:

Questo è il modo corretto di andare. Lo stato in cui si trova una risorsa per quanto riguarda il log specifico del dominio (ovvero la logica aziendale) è una questione relativa al tipo di contenuto della rappresentazione della risorsa.

Qui ci sono due concetti di differenza che sono stati combinati e che sono in realtà diversi. Uno è lo stato del trasferimento di stato tra client e server di una risorsa e l'altro è lo stato della risorsa stessa in qualsiasi contesto il dominio aziendale sottostà ai diversi stati di quella risorsa. Quest'ultimo non ha nulla a che fare con i codici di stato HTTP.

Ricordare che i codici di stato HTTP corrispondono al trasferimento di stato tra client e server della risorsa gestita, indipendentemente dai dettagli di quella risorsa. Quando GET una risorsa il tuo cliente chiede al server una rappresentazione di una risorsa nello stato corrente in cui si trova. Potrebbe essere un'immagine di un uccello, potrebbe essere un documento di Word, potrebbe essere la temperatura esterna corrente . Il protocollo HTTP non interessa. Il codice di stato HTTP corrisponde al risultato di tale richiesta. Il POST dal client al server ha trasferito una risorsa sul server, dove il server ha quindi fornito un URL che il client può visualizzare? Sì? Quindi questa è una risposta 201 Created .

La risorsa potrebbe essere una prenotazione aerea attualmente in stato "da rivedere". Oppure potrebbe essere un ordine di acquisto del prodotto in stato "approvato". Questi stati sono specifici del dominio e non di ciò che riguarda il protocollo HTTP. Il protocollo HTTP si occupa del trasferimento di risorse tra client e server.

Il punto di REST e HTTP è che i protocolli non si preoccupano dei dettagli delle risorse. Questo è di proposito, non si occupa dei problemi specifici del dominio in modo che possa essere utilizzato senza dover conoscere nulla sui problemi specifici del dominio. Non reinterpreta cosa significano i codici di stato HTTP in ogni contesto (un sistema di prenotazione delle compagnie aeree, un sistema di elaborazione delle immagini, un sistema di sicurezza video, ecc.)

Il materiale specifico del dominio è per il client e il server per capire tra loro in base al Content Type della risorsa. Il protocollo HTTP è agnostico a questo.

Per quanto riguarda il modo in cui il cliente capisce che la risorsa Richiesta ha cambiato stato, il polling è la soluzione migliore perché mantiene il controllo sul client e non presuppone una connessione ininterrotta. Soprattutto se saranno potenzialmente le ore fino a quando lo stato non cambierà. Anche se hai detto all'inferno con REST hai intenzione di mantenere aperta la connessione, tenerla aperta per ore e assumere che nulla andrà storto sarebbe una cattiva idea. Cosa succede se l'utente chiude il client o la rete si spegne. Se la granularità è ore, il client può richiedere lo stato ogni pochi minuti fino a quando la richiesta cambia da "in sospeso" a "fatto".

Spero che aiuti a chiarire le cose

    
risposta data 21.04.2016 - 17:48
fonte
2

Codice di stato HTTP per risorsa non ancora disponibile suggerisce di restituire una risposta di conflitto 409, piuttosto che una risposta 404, nel caso che una risorsa non esiste perché è nel mezzo di essere generato.

Dalla specifica w3 :

10.4.10 409 Conflict

The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough

information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.

Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being used and the entity being PUT included changes to a resource which conflict with those made by an earlier (third-party) request, the server might use the 409 response to indicate that it can't complete the request. In this case, the response entity would likely contain a list of the differences between the two versions in a format defined by the response Content-Type.

Questo è leggermente imbarazzante, poiché il codice 409 è "consentito solo in situazioni in cui è previsto che l'utente possa essere in grado di risolvere il conflitto e inviare nuovamente la richiesta". Suggerisco che il corpo della risposta includa un messaggio (possibilmente in un formato di risposta che corrisponda al resto dell'API) come "Questa risorsa è attualmente in fase di generazione, è stata avviata alle [TIME] e si stima che venga completata alle [TIME]. riprova più tardi. "

Si noti che suggerirei l'approccio 409 solo se è molto probabile che l'utente che richiede la risorsa sia anche l'utente che ha avviato la generazione di tale risorsa. Gli utenti non coinvolti nella generazione della risorsa troveranno un errore 404 meno confuso.

    
risposta data 20.04.2016 - 18:55
fonte
2

Ho trovato ragionevoli i suggerimenti di questo blog: REST e lavori di lunga durata .

Per riassumere:

  1. Il server restituisce il codice "202 Accettato" con l'intestazione "Posizione" impostata su un URI per consentire al client di verificare lo stato, ad es. "/ Queue / 12345".
  2. Fino al termine dell'elaborazione, il server risponde alle query di stato con "200 OK" e alcuni dati di risposta mostrano lo stato del lavoro.
  3. Al termine dell'elaborazione, il server risponde alle query di stato con "303 Visualizza altro" e "Posizione" contenente URI al risultato finale.
risposta data 16.11.2018 - 18:58
fonte

Leggi altre domande sui tag