Ho un codice (vedi sotto) scritto in Go, che si suppone che "fan-out" le richieste HTTP e raccolga/aggreghi i dettagli indietro.Come gestire gli errori di timeout HTTP e l'accesso ai codici di stato in golang
I'm new to golang and so expect me to be a nOOb and my knowledge to be limited
L'output del programma è attualmente qualcosa come:
{
"Status":"success",
"Components":[
{"Id":"foo","Status":200,"Body":"..."},
{"Id":"bar","Status":200,"Body":"..."},
{"Id":"baz","Status":404,"Body":"..."},
...
]
}
C'è un server locale in esecuzione che è volutamente lenta (posti letto per 5 secondi e poi restituisce una risposta). Ma ho altri siti elencati (vedi il codice qui sotto) che a volte attivano anche un errore (se si sbaglia, allora va bene).
Il problema che ho al momento è il modo migliore per gestire questi errori, e in particolare gli errori relativi al "timeout"; nel senso che non sono sicuro di come riconoscere se un errore è un timeout o qualche altro errore?
Al momento ottengo un errore di coperta indietro per tutto il tempo: (! Si spera per timeout)
Get http://localhost:8080/pugs: read tcp 127.0.0.1:8080: use of closed network connection
Dove http://localhost:8080/pugs
sarà generalmente l'url che non è riuscita. Ma come puoi vedere dal codice (sotto), non sono sicuro di come determinare il codice di errore sia correlato a un timeout né come accedere al codice di stato della risposta (attualmente sono solo blanket impostandolo su 404
ma ovviamente non è giusto - se il server dovesse commettere errori mi aspetterei qualcosa di simile a un codice di stato 500
e ovviamente mi piacerebbe riflettere che nella risposta aggregata io rispedisco indietro).
Il codice completo può essere visualizzato di seguito. Qualsiasi aiuto apprezzato.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"sync"
"time"
)
type Component struct {
Id string `json:"id"`
Url string `json:"url"`
}
type ComponentsList struct {
Components []Component `json:"components"`
}
type ComponentResponse struct {
Id string
Status int
Body string
}
type Result struct {
Status string
Components []ComponentResponse
}
var overallStatus string = "success"
func main() {
var cr []ComponentResponse
var c ComponentsList
b := []byte(`{"components":[{"id":"local","url":"http://localhost:8080/pugs"},{"id":"google","url":"http://google.com/"},{"id":"integralist","url":"http://integralist.co.uk/"},{"id":"sloooow","url":"http://stevesouders.com/cuzillion/?c0=hj1hfff30_5_f&t=1439194716962"}]}`)
json.Unmarshal(b, &c)
var wg sync.WaitGroup
timeout := time.Duration(1 * time.Second)
client := http.Client{
Timeout: timeout,
}
for i, v := range c.Components {
wg.Add(1)
go func(i int, v Component) {
defer wg.Done()
resp, err := client.Get(v.Url)
if err != nil {
fmt.Printf("Problem getting the response: %s\n", err)
cr = append(cr, ComponentResponse{
v.Id,
404,
err.Error(),
})
} else {
defer resp.Body.Close()
contents, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Problem reading the body: %s\n", err)
}
cr = append(cr, ComponentResponse{
v.Id,
resp.StatusCode,
string(contents),
})
}
}(i, v)
}
wg.Wait()
j, err := json.Marshal(Result{overallStatus, cr})
if err != nil {
fmt.Printf("Problem converting to JSON: %s\n", err)
return
}
fmt.Println(string(j))
}
Molto probabilmente estranei a il tuo problema, ma hai una corsa di dati che si aggiunge a 'cr'. Non è possibile scrivere la stessa variabile da più goroutine senza sincronizzazione. Potresti voler costruire/correre con il [rivelatore di gare] (https://blog.golang.org/race-detector). –
Grazie per il commento. Cercherò invece di utilizzare i canali +. Indagherò quel rilevatore di gare :-) – Integralist
Se la chiamata del cliente restituisce un errore, non c'è alcun codice di stato, perché non c'era una richiesta http completa. Non c'è molto che puoi fare con un errore a quel punto, ma in go1.5 un client. Il timeout restituirà almeno un messaggio migliore in un errore net.Error. – JimB