设置内置的HTTP请求超时的最佳方法是什么?

huangapple go评论167阅读模式
英文:

The best way to set the timeout on built-in HTTP request

问题

设置内置http.NewRequest的超时时间的最佳方法是什么?目前,我正在使用http.Client的Timeout属性,它覆盖整个请求过程,但是否有更好的方法,例如使用context.WithDeadlinecontext.WithTimeout?如果有,它是如何工作的?如何为http.NewRequest设置context.WithDeadline解决方案?

以下是我目前的解决方案:

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

请注意,这是一个示例代码,你可以根据自己的需求进行调整。

英文:

What is the best way to setup a timeout on built-in http NewRequest? Currently, I'm using http.Client.Timeout which is cover the entire exchange, but is there something better for example context.WithDeadline or context.WithTimeout. If yes how is it working, how can I setup a context.WithDeadline solution for the http.NewRequest?

There is my current solution:

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

得分: 1

从context.WithDeadline中获取新的上下文。请参阅文档
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)
}
英文:

Get new context from context.WithDeadline. See documentation.
WithTimeout just returns WithDeadline(parent, time.Now().Add(timeout)).

package main

import (
	&quot;context&quot;
	&quot;io&quot;
	&quot;log&quot;
	&quot;net/http&quot;
	&quot;os&quot;
	&quot;time&quot;
)

func getContent(ctx context.Context) {
	req, err := http.NewRequest(&quot;GET&quot;, &quot;http://example.com&quot;, 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)
}

If you want to make cancel trigger on main:

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

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

	getContent(ctx)
}

huangapple
  • 本文由 发表于 2017年7月5日 01:49:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/44911726.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定