如何处理客户端超时错误?

时间:2016-02-12 09:11:18

标签: go

我正在尝试对服务器进行HTTP调用,并使用10秒的客户端超时。我正在处理它的当前(不正确)方式是这样的:

package checks

import "net/http"
import "fmt"
import "log"
import "time"
import "strings"

var client = &http.Client{Timeout: 10 * time.Second}

func HttpCheck(url string) (string, error) {
    log.Printf("initiating http get to %s\n", url)
    resp, err := client.Get(url)

    if err != nil {
        if strings.Contains(err.Error(), "Client.Timeout") {
            return "loading", nil
        } else {
            log.Printf("error while getting url : %s\n", err.Error())
            return "", err
        }
    }
    defer resp.Body.Close()
    if resp.StatusCode != 200 {
        log.Printf("got a non 200 response: %d", resp.StatusCode)
        return "", fmt.Errorf("Server returned non 200 status: %d", resp.StatusCode)
    }
    log.Println("all is well, returning a success")
    return "up", nil
}

Go httpError引发的实际错误未导出。

如何可靠地处理客户端超时?

1 个答案:

答案 0 :(得分:0)

鉴于标准库中的当前超时错误处理状态(有望很快得到改进,通常是即将发布的1.6版本),您可以使用goroutines,channel和timers来检查超时条件。

例如:

func httpCheck(url string) (string, error) {
    // channels for result, and error
    responseChan := make(chan string, 1)
    errChan := make(chan error, 1)

    timeout := 30 * time.Second

    // run http get asynchronously
    go func() {
        client := &http.Client{
            Timeout: timeout + 5.Second, // use a longer timeout so the goroutine does not block forever
        }

        resp, err := client.Get(url)
        if err != nil {
            errChan <- err
            return
        }

        defer resp.Body.Close()

        if resp.StatusCode != http.StatusOK {
            errChan <- fmt.Errorf("Server returned non 200 status: %d", resp.StatusCode)
            return
        }
        responseChan <- "up"
    }()

    // wait for the first thing to happen, either
    // an error, a timeout, or a result
    select {
    case err := <-errChan:
        return nil, err
    case <-time.After(timeout):
        return nil, errors.New("timeout")
    case result := <-responseChan:
        return result, nil
    }
}