Dovrei usare i codici di stato HTTP per descrivere eventi a livello di applicazione


54

Diversi server con cui ho avuto a che fare restituiranno HTTP 200 per richieste che il client dovrebbe considerare un errore, con qualcosa come "successo: falso" nel corpo.

Questa non mi sembra una corretta implementazione dei codici HTTP, in particolare in caso di autenticazione fallita. Ho letto i codici di errore HTTP in modo piuttosto sintetico in quanto "4xx" indica che la richiesta non deve essere ripetuta fino a quando non viene modificata, mentre "5xx" indica che la richiesta può essere valida o meno e può essere ritentata, ma non ha avuto esito positivo. In questo caso 200: login fallito, o 200: impossibile trovare quel file, o 200: parametro mancante x, sembra decisamente sbagliato.

D'altra parte, ho potuto vedere l'argomentazione sostenuta che "4xx" dovrebbe indicare solo un problema strutturale con la richiesta. Quindi è corretto restituire 200: utente / password errati anziché 401 non autorizzati perché al client è consentito effettuare la richiesta, ma risulta errato. Questo argomento potrebbe essere riassunto in quanto, se il server fosse in grado di elaborare la richiesta e prendere una decisione, il codice di risposta dovrebbe essere 200 e spetta al cliente controllare il corpo per ulteriori informazioni.

Fondamentalmente, questa sembra essere una questione di preferenza. Ma questo non è soddisfacente, quindi se qualcuno ha una ragione per cui uno di questi paradigmi è più corretto, vorrei saperlo.


9
success: falseimplica che la richiesta non è riuscita e tu lo sai. Dovrebbe essere un 500. Qualcosa come il tuo nome utente / password errati sarebbe un 401. Non è così ambiguo.
Pete,


4
Questa è una di quelle domande che possono invocare guerre di religione penso. Per un'API RESTful, la risposta è chiara, ma esistono altri tipi di API in cui HTTP viene trattato proprio come un livello di trasporto e, in questi casi, gli errori dell'applicazione non devono essere trasferiti a quel livello.
Gort il robot il

5
Quando non sono davvero sicuro dello stato http da restituire, è sempre allettante andare con 418 "Sono una teiera".
joshp,

1
Un esempio sono le richieste e le risposte multiple (in batch) . Il batch non è una cosa riposante; ma i problemi di efficienza pratica spesso richiedono un certo supporto per il raggruppamento rispetto a problemi di eleganza.
rwong,

Risposte:


35

Domanda interessante.

Fondamentalmente, possiamo ridurlo nel modo giusto per classificare le cose in termini analoghi ai livelli OSI. HTTP è comunemente definito come protocollo a livello di applicazione e HTTP è in effetti un protocollo client / server generico.

Tuttavia, in pratica, il server è quasi sempre un dispositivo di inoltro e il client è un browser Web, responsabile dell'interpretazione e del rendering del contenuto: il server passa le cose a un'applicazione arbitraria e tali applicazioni restituiscono script arbitrari che il browser è responsabile dell'esecuzione. L'interazione HTTP stessa - i moduli di richiesta / risposta, i codici di stato e così via - è principalmente una questione di come richiedere, servire e rendere i contenuti arbitrari nel modo più efficiente possibile, senza interferire. Molti dei codici di stato e delle intestazioni sono infatti progettati per questi scopi.

Il problema con il tentativo di trasferire sulle spalle il protocollo HTTP per la gestione di flussi specifici dell'applicazione è che ti rimane una delle due opzioni: 1) Devi rendere la tua logica di richiesta / risposta un sottoinsieme delle regole HTTP; oppure 2) È necessario riutilizzare determinate regole e quindi la separazione delle preoccupazioni tende a diventare confusa. All'inizio può sembrare bello e pulito, ma penso che sia una di quelle decisioni di progettazione che rimpiangi man mano che il tuo progetto si evolve.

Pertanto, direi che è meglio essere espliciti sulla separazione dei protocolli. Consenti al server HTTP e al browser Web di fare le proprie cose e l'app di fare le proprie cose. L'app deve essere in grado di fare richieste e ha bisogno delle risposte - e la sua logica su come richiedere, come interpretare le risposte, può essere più (o meno) complessa della prospettiva HTTP.

L'altro vantaggio di questo approccio, che vale la pena menzionare, è che le applicazioni, in generale, non dovrebbero dipendere da un protocollo di trasporto sottostante (da un punto di vista logico). Lo stesso HTTP è cambiato in passato e ora abbiamo avviato HTTP 2, a seguito di SPDY. Se visualizzi la tua app come nient'altro che un plug-in di funzionalità HTTP, potresti rimanere bloccato lì quando subentrano nuove infrastrutture.


8
Molto perspicace. L'argomento più forte qui è la discrepanza (impedenza) tra i codici di stato HTTP e i valori di ritorno della tua app. Questo può diventare un incubo a lungo termine. Inoltre, sostengo fortemente la separazione delle preoccupazioni tra il trasporto (HTTP) e il payload (dati dell'app). Se si digita erroneamente l'URL di un endpoint del servizio, si ottiene un 404. Se si richiede al servizio un elemento inesistente, viene visualizzato un messaggio specifico per l'app (magari con informazioni aggiuntive che è possibile utilizzare per risolvere il problema).

2
Se si digita male l'URL, si potrebbe anche non finire sul server giusto e quindi tutto potrebbe succedere.
gnasher729,

Questo è un aspetto gradevolmente sfumato. Penso che il problema dell'HTTP che diventa uno strato di pseudo-trasporto sia il vero problema nel prendere una decisione. Mi capita spesso di rispondere a questa domanda quando hai un server nginx o apache che esegue il proxy di un server nodejs, dove il proxy ha già delle regole per l'invio di questi codici e la domanda diventa se è appropriato che il back-end sia conforme allo standard. In alcuni di questi casi potrebbe esserci un motivo progettuale per non inviare un codice di errore, poiché nginx potrebbe interpretarlo come "back-down".
Kagan Mattson,

4
Sono d'accordo. Non c'è nulla di sbagliato nel segnalare un errore a livello di applicazione in una risposta HTTP 200. Il 200 indica che la richiesta / risposta HTTP stessa ha avuto esito positivo, senza dire nulla sul suo contenuto o sulla semantica a livello di applicazione invocata in quel momento.
Corse di leggerezza con Monica il

22

Questa domanda è un po 'basata sull'opinione, ma in entrambi i casi.

Per come la vedo io, 200 possono servire "errori soft". Quando si tratta di creare API, cerco di distinguere tra questi e "errori gravi".

Gli "errori soft" verranno visualizzati con un codice di stato di 200, ma conterranno una descrizione dell'errore e uno stato di successo di false. Gli "errori soft" si verificano solo quando il risultato è "come previsto", ma non un successo nel senso più stretto.

È importante notare che gli "errori soft" sono un suggerimento per l'implementatore. Pertanto, è importante fornire ulteriori informazioni sull'errore, come un messaggio di errore leggibile dall'uomo e / o una sorta di codice che può essere utilizzato per fornire un feedback all'utente finale. Questi errori forniscono all'implementatore (e all'utente finale) maggiori informazioni su ciò che è accaduto sul lato server delle cose.

Ad esempio, supponiamo di avere un'API con una funzione di ricerca, ma durante una ricerca non viene prodotto alcun risultato. Questo non è errato, ma non è neppure un "successo", non nel senso più stretto della definizione.

Esempio formattato come JSON:

{
    "meta" {
        "success": false,
        "message": "Search yielded no results",
        "code": "NORESULTS"
    }
    "data": []
}

"Errori gravi", d'altra parte, verrà servito con un codice di stato che è raccomandato per l'errore. Utente non registrato? - 403 / 401. Ingresso non valido? - 400. Errore del server? - 50X. E così via.

Ancora una volta, è un po 'basato sull'opinione. Alcune persone vogliono trattare tutti gli errori allo stesso modo, "errore duro" tutto. Nessun risultato trovato? Questo è un 404! Dall'altro lato della medaglia, nessun risultato di ricerca? - Questo è come previsto, nessun errore.

Un altro fattore importante da prendere in considerazione è la tua architettura, per esempio; se interagisci con la tua API utilizzando le richieste XHR di JavaScript e jQuery o AngularJS. Questi "errori gravi" dovranno essere gestiti con un callback separato, mentre gli "errori soft" possono essere gestiti con il callback "successo". Non rompendo nulla, il risultato è ancora "come previsto". Il codice sul lato client può quindi esaminare lo stato di successo e il codice (o il messaggio). E stampalo per l'utente finale.


2
In realtà, classificarlo come un errore a livello di API è una decisione curiosa. Anche se il cliente può, a sua discrezione, classificarlo come imprevisto a livello di utente.
Deduplicatore,

1
Ci sono molte cose che devono essere prese in considerazione. Tutto dipende dall'implementazione dell'API. È anche di nuovo, un po 'basato sull'opinione e anche su ciò che l'API definisce "successo" e / o "errore". Il "success": falseflag è più di un suggerimento per l'implementatore che qualcosa sta succedendo . Di solito dovrebbe andare con un codice di stato interno . Uno "code": "NORESULTS"o un codice numerico, qualunque sia il creatore delle fantasie API. È principalmente lì, quindi chiunque implementa l'API può dedurre informazioni su ciò che è accaduto sul server.
die maus,

15

Esistono due aspetti di un'API: lo sforzo di implementare l'API e lo sforzo di tutti i client di utilizzare correttamente l'API.

Come autore del client, so che quando invio una richiesta a un server Web, potrei ricevere un errore (mai parlato correttamente con il server) o una risposta con un codice di stato. Devo gestire gli errori. Devo gestire una buona risposta. Devo gestire risposte "cattive" attese, documentate. Devo gestire tutto ciò che ritorna.

Nel progettare l'API, dovresti esaminare qual è la più semplice da elaborare per il client. Se il client invia una richiesta ben formata e puoi fare ciò che la richiesta ti chiede di fare, allora dovresti dare una risposta nell'intervallo 200 (ci sono alcuni casi in cui un numero diverso da 200 in quell'intervallo è appropriato).

Se il client chiede "dammi tutti i record come ...", e ci sono zero, allora un 200 con successo e una matrice di zero record è del tutto appropriato. I casi che menzioni:

"Accesso fallito" di solito dovrebbe essere un 401. "Impossibile trovare il file" dovrebbe essere un 404. "Il parametro mancante x" dovrebbe essere qualcosa intorno a 500 (in realtà, un 400 se il server capisce che la richiesta è sbagliata e 500 se il server è totalmente confuso dalla mia richiesta e non ha idea di cosa stia succedendo). Restituire 200 in questi casi è inutile. Significa solo come l'autore di un client, non posso semplicemente guardare il codice di stato, devo studiare anche la risposta. Non posso semplicemente dire "status 200, fantastico, ecco i dati".

Soprattutto il "parametro mancante" - non è qualcosa che avrei mai gestito . Significa che la mia richiesta non è corretta. Se la mia richiesta non è corretta, non ho un fallback per correggere quella richiesta errata - per iniziare invierei una richiesta corretta. Ora sono costretto a gestirlo. Ottengo un 200 e devo verificare se c'è una risposta "parametro mancante". È terribile.

Alla fine, ci sono una dozzina o due codici di stato per gestire molte situazioni diverse e dovresti usarle.


3
Quando mi connetto a un'API, personalmente preferirei ottenere 200 su un 'file non trovato' quando mi connetto a un endpoint valido, poiché la mia gestione HTTP non deve sanguinare nel livello che gestisce l'API su di esso.
whatsisname

4
"Parametro mancante x" dovrebbe essere un 400 BAD_REQUEST perché è il client che fa qualcosa di sbagliato. 500 INTERNAL_SERVER_ERROR dovrebbe essere riservato per i casi in cui il server sta facendo la cosa sbagliata. Un 500 implica che il client potrebbe essere in grado di riprovare. Un 400 implica che qualcuno dovrebbe andare a riparare il client.
Gort il robot il

1
Se stai scrivendo un'interfaccia RESTful, l'URL identifica un oggetto specifico e quindi un 404 è appropriato. È concettualmente lo stesso si /customers/premium/johndoe.jsonriferisce a un cliente che non si trova nel database e se si /files/morefiles/customers.htmlriferisce a una pagina non presente nel filesystem.
Gort il robot il

@whatsisname Quello che stai dicendo ha senso perché non è chiaro se è l'endpoint che è cattivo o la risorsa non esiste. È inoltre possibile affermare che, indipendentemente dal fatto che l'endpoint sia valido o meno, non esiste alcuna risorsa a tale indirizzo, pertanto 404in entrambi i casi è corretto.
Pete,

2
Una cosa che non ho visto menzionato è che quando si trasferiscono gli errori dell'applicazione sui codici di stato HTTP, si potrebbero perdere informazioni. Se l'app restituisce solo un 404 e nient'altro, non sai se è stato perché l'API ha restituito un 404 o perché il server non è riuscito a trovare il file. Ciò potrebbe aggiungere un ulteriore passaggio al tuo debug.
Amadeus Dr Zaius,
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.