一尘不染

如何过早关闭/中止Golang http.Client POST

go

我正在使用http.Client长轮询的客户端实现:

resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonPostBytes))
if err != nil {
    panic(err)
}
defer resp.Body.Close()

var results []*ResponseMessage
err = json.NewDecoder(resp.Body).Decode(&results)  // code blocks here on long-poll

是否有一种标准方法可以从客户端抢占/取消请求?

我想调用resp.Body.Close()会做到这一点,但是我不得不从另一个goroutine调用它,因为通常在读取长轮询的响应时,客户端通常已经被阻塞。

我知道有一种方法可以通过设置超时http.Transport,但是我的应用逻辑需要根据用户操作(而不只是超时)进行取消。


阅读 335

收藏
2020-07-02

共1个答案

一尘不染

不,client.Post是90%不需要取消请求的用例的便捷包装。

重新实现您的客户端以访问具有CancelRequest()函数的基础传输对象可能就足够了。

只是一个简单的例子:

package main

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

func main() {
    req, _ := http.NewRequest("GET", "http://google.com", nil)
    tr := &http.Transport{} // TODO: copy defaults from http.DefaultTransport
    client := &http.Client{Transport: tr}
    c := make(chan error, 1)
    go func() {
        resp, err := client.Do(req)
        // handle response ...
        _ = resp
        c <- err
    }()

    // Simulating user cancel request channel
    user := make(chan struct{}, 0)
    go func() {
        time.Sleep(100 * time.Millisecond)
        user <- struct{}{}
    }()

    for {
        select {
        case <-user:
            log.Println("Cancelling request")
            tr.CancelRequest(req)
        case err := <-c:
            log.Println("Client finished:", err)
            return
        }
    }
}
2020-07-02