golang 的 http 请求, transport.CancelRequest 与 client.Timeout 有冲突

2020-06-22 15:36:57 +08:00
 howellz

两个需求:

  1. 用户可以随时终止请求。
  2. 用户可以修改超时值,比如 20s ;

对于第一个需求,设置了 client.Transport,并在合适的位置调用其 CancelRequest()接口; 对于第二个需求,设置了 client.Timeout ;

但是调试中发现,如果设置了 client.Timeout,则 Transport.CancelRequest()就不再起效。 注释掉 Timeout 就可以生效。

代码如下:

package main

import (
	"fmt"
	"net/http"
	"time"
)

func main() {
	trans := &http.Transport{}
	client := &http.Client{
		Transport: trans,
		Timeout:   time.Second * (30), // 这一行不注释就无法 CancelRequest
	}
	req, err := http.NewRequest("GET", "https://www.google.com", nil)
	if err != nil {
		panic(err)
	}

	go func() {
		time.Sleep(time.Second * time.Duration(1))
		fmt.Printf("%v: abort\n", time.Now())
		trans.CancelRequest(req)
	}()

	fmt.Printf("%v: start ...\n", time.Now())
	_, err = client.Do(req)
	fmt.Printf("%v: done\n", time.Now())
	if err != nil {
		fmt.Println(err.Error())
	}
}

请问我该怎么办?

1659 次点击
所在节点    Go 编程语言
5 条回复
howellz
2020-06-22 15:47:40 +08:00
对了,自己不希望用 Timeou 来调用 CanceRequest,还是希望用 client 自己的 timeout 可以么?
guonaihong
2020-06-22 16:04:35 +08:00
了解下 WithContext 。我在 gout 里面的超时就是用这个 API 实现的。context 可超时取消,可以调用 cancel 取消。
这是官方 WithContext 的文档
https://golang.google.cn/pkg/net/http/#Request.WithContext

## 这是 gout 里面使用 WithContext 的例子
https://github.com/guonaihong/gout/blob/master/_example/05b-cancel.go
SingeeKing
2020-06-22 16:20:58 +08:00
Deprecated: Use Request.WithContext to create a request with a cancelable context instead
reus
2020-06-22 20:56:15 +08:00
howellz
2020-09-10 19:00:19 +08:00
谢谢各位的回复,我找到了一个比较简单的方法:

```
c := make(chan struct{})
req.Cancel = c

go func() {
time.Sleep(time.Second * time.Duration(1))
fmt.Printf("%v: abort\n", time.Now())
//trans.CancelRequest(req)
close(c) // 用这句取代 CancelRequest
}()

```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/683782

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX