Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Sfondo
Gli errori in MSAL sono destinati agli sviluppatori di app per la risoluzione dei problemi e non per la visualizzazione agli utenti finali.
Obiettivi relativi agli errori di MSAL
- Fornisci informazioni diagnostiche all'utente e per i ticket che possono essere utilizzate per individuare bug o configurazioni errate del client
- Rilevare gli errori che sono transitori e che possono essere ritentati
- Consentire all'utente di identificare determinati errori a cui il programma può rispondere, in modo da informare l'utente della necessità di eseguire una registrazione
Gestione degli errori in Go rispetto ad altri linguaggi
La maggior parte dei linguaggi moderni usa errori basati su eccezioni. In poche parole, si "solleva" un'eccezione e questa deve essere intercettata da una routine più in alto nello stack, altrimenti il programma finirà per arrestarsi in modo anomalo.
Go non usa eccezioni, ma si basa su più valori restituiti, uno dei quali può essere il tipo di interfaccia di errore predefinito. Spetta all'utente decidere cosa fare.
Tipi di errore personalizzati in Go
Gli errori possono essere creati in Go usando errors.New() o fmt.Errorf() per creare un "errore".
Gli errori personalizzati possono essere creati in diversi modi. Uno dei modi più affidabili consiste semplicemente nel soddisfare l'interfaccia di errore:
type MyCustomErr struct {
Msg string
}
func (m MyCustomErr) Error() string { // This implements "error"
return m.Msg
}
Implementazione della gestione degli errori lato client
Gli errori sul lato client indicano una configurazione errata o il passaggio di argomenti non validi non ripristinabili. Non è possibile riprovare.
Questi errori possono essere semplicemente errori Go standard creati da errors.New() o fmt.Errorf(). Se più avanti avremo bisogno di un errore personalizzato, potremo introdurlo, ma per ora i messaggi di errore devono solo spiegare chiaramente quale sia stato il problema.
Implementazione della gestione degli errori lato server
Gli errori sul lato servizio si verificano quando un RPC esterno risponde con un codice di errore HTTP o restituisce un messaggio che include un errore.
Questi errori possono essere transitori (rallentare) o permanenti (HTTP 404). Per fornire gli obiettivi di diagnostica, è necessaria la possibilità di distinguere questi errori da altri errori.
L'implementazione corrente include un tipo specializzato che acquisisce qualsiasi errore dal server:
// CallErr represents an HTTP call error. Has a Verbose() method that allows getting the
// http.Request and Response objects. Implements error.
type CallErr struct {
Req *http.Request
Resp *http.Response
Err error
}
// Errors implements error.Error().
func (e CallErr) Error() string {
return e.Err.Error()
}
// Verbose prints a versbose error message with the request or response.
func (e CallErr) Verbose() string {
e.Resp.Request = nil // This brings in a bunch of TLS stuff we don't need
e.Resp.TLS = nil // Same
return fmt.Sprintf("%s:\nRequest:\n%s\nResponse:\n%s", e.Err, prettyConf.Sprint(e.Req), prettyConf.Sprint(e.Resp))
}
L'utente visualizzerà sempre il messaggio di errore più conciso che forniamo. Possono indicare se si tratta di un errore sul lato server usando il pacchetto di errore Go:
var callErr CallErr
if errors.As(err, &callErr) {
...
}
Forniamo una Verbose() funzione in grado di ottenere il messaggio più dettagliato da qualsiasi errore che forniamo:
fmt.Println(errors.Verbose(err))
Se è necessaria un'ulteriore differenziazione, possiamo aggiungere errori personalizzati che usano il wrapping degli errori di Go basato su CallErr per raggiungere i nostri obiettivi diagnostici, ad esempio per rilevare quando riprovare una chiamata a causa di errori temporanei.
CallErr viene sempre generata dal pacchetto comm (che gestisce tutte le richieste HTTP) e ha un aspetto simile al seguente:
return nil, errors.CallErr{
Req: req,
Resp: reply,
Err: fmt.Errorf("http call(%s)(%s) error: reply status code was %d:\n%s", req.URL.String(), req.Method, reply.StatusCode, ErrorResponse), //ErrorResponse is the json body extracted from the http response
}
Decisioni future
La possibilità di riprovare le chiamate deve avere una responsabilità centralizzata. L'utente lo sta facendo o il client lo sta eseguendo.
Se la responsabilità deve ricadere sull'utente, il nostro pacchetto di gestione degli errori includerà una CanRetry() funzione che indicherà all'utente se l'errore che gli viene restituito può essere ritentato. Si basa sul codice di errore HTTP ed eventualmente sul tipo di errore restituito. Includerebbe anche un tempo di attesa se il server restituisse un intervallo di tempo da attendere.
Altrimenti lo faremo internamente e i nuovi tentativi saranno gestiti da noi.