当请求有正文时,Go http 上下文无法捕获取消信号(curl、postman)

可以使用以下简单的 go 代码片段重现该问题:


简单的http服务器:


package main


import (

    "fmt"

    "log"

    "net/http"

    "time"

)


func handler(w http.ResponseWriter, r *http.Request) {

    go func(done <-chan struct{}) {

        <-done

        fmt.Println("message", "client connection has gone away, request got cancelled")

    }(r.Context().Done())


    time.Sleep(30 * time.Second)

    fmt.Fprintf(w, "Hi there, I love %s!\n", r.URL.Path[1:])

}


func main() {

    http.HandleFunc("/", handler)

    log.Fatal(http.ListenAndServe(":8080", nil))

}

GET从http服务器上方开始,如果我使用curl(也有邮递员)发送一个简单的请求,例如:

curl -X GET http://localhost:8080/

然后按Ctrl+C终止请求,然后我可以在服务器端看到打印的消息:

message client connection has gone away, request got cancelled

以上是我期望的正确行为:模拟当客户端消失时服务器可以捕获它的情况,然后尽早取消所有不必要的工作。

但是,当我发送一个带有请求正文的 POST 请求时,这种预期的行为不会发生,<-done信号被捕获,直到请求截止日期满足。

curl -X POST http://localhost:8080/ -H 'Content-Type: application/json' -d '{}'

总结一下我的问题:

  1. 为什么以及如何curl(postman) GETPOST带或不带请求正文)请求产生如此大的差异?

  2. 我应该如何使用 go context 包正确处理这种情况,我的意思是尽快捕获客户端消失的信号,从而进一步取消服务器端不必要的工作以尽早释放资源。


牛魔王的故事
浏览 89回答 1
1回答

慕勒3428872

读取请求正文以检测客户端何时关闭连接:func handler(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; go func(done <-chan struct{}) {&nbsp; &nbsp; &nbsp; &nbsp; <-done&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("message", "client connection has gone away, request got cancelled")&nbsp; &nbsp; }(r.Context().Done())&nbsp; &nbsp; io.Copy(ioutil.Discard, r.Body) // <-- read the body&nbsp; &nbsp; time.Sleep(30 * time.Second)&nbsp; &nbsp; fmt.Fprintf(w, "Hi there, I love %s!\n", r.URL.Path[1:])}net/http 服务器通过读取连接来检查关闭的连接。在应用程序开始读取请求正文(如果有)之前,不会开始读取。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go