2015-08-16 31 views
5

Mam pewien kod (patrz poniżej) napisany w Go, który ma "wysyłać" żądania HTTP, i zestawiać/agregować szczegóły z powrotem.Jak radzić sobie z błędami limitu czasu HTTP i uzyskiwać dostęp do kodów statusu w golang

I'm new to golang and so expect me to be a nOOb and my knowledge to be limited

Wyjście programu jest obecnie coś takiego:

{ 
    "Status":"success", 
    "Components":[ 
     {"Id":"foo","Status":200,"Body":"..."}, 
     {"Id":"bar","Status":200,"Body":"..."}, 
     {"Id":"baz","Status":404,"Body":"..."}, 
     ... 
    ] 
} 

Jest tam lokalny serwer, który bieg jest celowo powolne (śpi przez 5 sekund, a następnie zwraca odpowiedź). Ale mam też inne witryny (patrz kod poniżej), które czasami wywołują również błąd (jeśli błąd, to jest w porządku).

Problem jaki mam w tej chwili, to jak najlepiej radzić sobie z tymi błędami, aw szczególności z błędami "timeoutowymi"; w którym nie jestem pewien, jak rozpoznać, czy awaria jest przekroczeniem limitu czasu, czy innym błędem?

W tej chwili pojawia się błąd koc cały czas (! Nadzieją timeout)

Get http://localhost:8080/pugs: read tcp 127.0.0.1:8080: use of closed network connection 

Gdzie http://localhost:8080/pugs będzie na ogół adres URL, który nie powiodło się. Ale jak widać z kodu (poniżej), nie jestem pewien, jak ustalić kod błędu jest związany z przekroczeniem limitu czasu, ani jak uzyskać dostęp do kodu statusu odpowiedzi (obecnie ustawiam go tylko na 404, ale oczywiście to nie jest w porządku - jeśli serwer popełnił błąd, oczekiwałbym czegoś w rodzaju kodu statusu 500 i oczywiście chciałbym to odzwierciedlić w zagregowanej odpowiedzi, którą odesłałem).

Pełny kod można zobaczyć poniżej. Każda pomoc doceniona.

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)) 
    } 
+0

Najprawdopodobniej niezwiązane Twój problem, ale masz wyścig danych dołączony do 'cr'. Nie można zapisać tej samej zmiennej z wielu goroutin bez synchronizacji. Możesz zbudować/uruchomić za pomocą [detektora wyścigów] (https://blog.golang.org/race-detector). –

+0

Dzięki za komentarz. Spróbuję wykorzystać kanały zamiast + Zbadam ten wykrywacz wyścigów :-) – Integralist

+1

Jeśli wywołanie klienta zwróci błąd, nie ma kodu statusu, ponieważ nie było pełnego żądania http. Nie można wiele zrobić z błędem w tym momencie, ale w wersji 1.5 klient.Timeout przynajmniej zwróci lepszy komunikat w sieci. Błąd. – JimB

Odpowiedz

-1

Go 1.5 release rozwiązać ten problem poprzez bardziej szczegółowe na temat rodzaju błędu to obsługiwane.

Więc jeśli widzisz ten przykład https://github.com/Integralist/Go-Requester/blob/master/requester.go#L38 zobaczysz, że jestem w stanie zastosować wzorzec regex do komunikatu błędu rozszyfrować, czy błąd był rzeczywiście limitu czasu lub nie

status := checkError(err.Error()) 

func checkError(msg string) int { 
    timeout, _ := regexp.MatchString("Timeout", msg) 

    if timeout { 
     return 408 
    } 

    return 500 
} 
+1

Nie groguj w ciągi błędów * najlepiej * jest niesamowicie delikatny; ciąg błędu nie jest * częścią żadnego interfejsu API. Interfejs ['net.Error'] (https://golang.org/pkg/net/#Error) definiuje dla tego metodę' Timeout'. –

+0

@Dave C dzięki za komentarz, ale nie jestem pewien, jak to, co zasugerowałeś, działa. Błąd, który otrzymuję z klienta. Przyjmij ciąg znaków. Nie ma żadnych metod. Nic więc do zapytania – Integralist

+0

To nie jest tylko ciąg znaków, to "błąd". Przekreślasz wszystko poza sformatowanym łańcuchem wyników, wywołując funkcję sprawdzania za pomocą 'err.Error()'. Zamiast tego powinieneś próbować asercji typu i innych kontroli. Tylko jeśli wszystko to nie zadziała, powinieneś a) złożyć raport o błędzie, który nie może być testowany, i b) jako brzydkie obejście (z dużym ostrzeżeniem) * może * grep w ciągu znaków (lub zmienić kod, do którego dzwonisz, aby zwrócić testowalny błąd i złożyć go jako żądanie zmiany w górę). –

1

Jeśli chcesz fan out następnie zagregowane wyniki i chcesz specyficzne zachowanie limitu czasu pakietu/http netto nie daję, to może chcesz używać goroutines i kanałów.

Właśnie obejrzałem ten film dzisiaj i przeprowadzi Cię przez dokładnie te scenariusze, korzystając z funkcji współbieżności aplikacji Go. Dodatkowo mówca Rob Pike jest autorytetem - wyjaśnia to znacznie lepiej niż ja.

https://www.youtube.com/watch?v=f6kdp27TYZs

+0

Downvote jest za opublikowanie godzinnego wideo. Gdzie jest odpowiedź? – circuitry