在内置HTTP请求中设置超时的最佳方法

时间:2017-07-04 17:49:15

标签: go timeout

内置 http NewRequest上设置超时的最佳方法是什么?目前,我正在使用http.Client。超时覆盖整个交易所,但有更好的内容,例如context.WithDeadlinecontext.WithTimeout。如果是,它是如何工作的,如何为context.WithDeadline设置http.NewRequest解决方案?

我目前的解决方案是:

func (c *Client) post(resource string, data url.Values, timeout time.Duration) ([]byte, error) {
    url := c.getURL(resource)
    client := &http.Client{
        Timeout: timeout * time.Millisecond,
    }
    req, err := http.NewRequest("POST", url, strings.NewReader(data.Encode()))
    if err != nil {
        return nil, err
    }
    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    return ioutil.ReadAll(resp.Body)
}

1 个答案:

答案 0 :(得分:1)

从context.WithDeadline获取新的上下文。见documentation。 WithTimeout只返回WithDeadline(parent,time.Now()。Add(timeout))。

package main

import (
    "context"
    "io"
    "log"
    "net/http"
    "os"
    "time"
)

func getContent(ctx context.Context) {
    req, err := http.NewRequest("GET", "http://example.com", nil)
    if err != nil {
        log.Fatal(err)
    }
    ctx, cancel := context.WithDeadline(ctx, time.Now().Add(3 * time.Second))
    defer cancel()

    req.WithContext(ctx)

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    io.Copy(os.Stdout, resp.Body)
}

func main() {
    ctx := context.Background()
    getContent(ctx)
}

如果你想在main上取消触发:

func main() {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)

    sc := make(chan os.Signal, 1)
    signal.Notify(sc, os.Interrupt)
    go func(){
        <-sc
        cancel()
    }()

    getContent(ctx)
}