在这种情况下,Go HTTP 处理程序 goroutine 是否应该立即退出?

Is the Go HTTP handler goroutine expected to exit immediately in this case?

我有一个这样的 Go HTTP 处理程序:

mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
    ctx, cancel := context.WithCancel(context.Background())

    defer cancel()

    if cn, ok := w.(http.CloseNotifier); ok {
        go func(done <-chan struct{}, closed <-chan bool) {
            select {
            case <-done:
            case <-closed:
                fmt.Println("client cancelled....................!!!!!!!!!")
                cancel()
            }
        }(ctx.Done(), cn.CloseNotify())
    }

    time.Sleep(5 * time.Second)

    fmt.Println("I am still running...........")

    fmt.Fprint(w, "cancellation testing......")
})

API 工作正常,然后在请求完成之前使用 curl 我故意用 Control-C 终止 curl 命令,在服务器端我确实看到 client cancelled....................!!!!!!!!! 被注销, 但过了一会儿 I am still running........... 也被注销了,我以为这个 goroutine 会立即终止!

那么,这是期望的行为,还是我做错了什么?

如果是预期的话,既然goroutine会完成它的工作,那么提前取消的意义何在?

如果我做错了,请帮我指出正确的方法。

您创建了一个可以取消的 contex.Context,当客户端关闭连接时您确实取消了它,但是您没有检查上下文,如果它被取消,您的处理程序也没有做任何不同的事情。上下文仅 携带 超时和取消信号,它没有权力也没有意图杀死/终止 goroutines。 goroutines 本身必须监视此类取消信号并对其采取行动。

所以您看到的是代码的预期输出。

你要的是监控上下文,如果取消了,return"immediately"从handler.

当然,如果您是"sleeping",则无法同时监视上下文。所以改为使用 time.After(),如本例所示:

mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    if cn, ok := w.(http.CloseNotifier); ok {
        go func(done <-chan struct{}, closed <-chan bool) {
            select {
            case <-done:
            case <-closed:
                fmt.Println("client cancelled....................!!!!!!!!!")
                cancel()
            }
        }(ctx.Done(), cn.CloseNotify())
    }

    select {
    case <-time.After(5 * time.Second):
        fmt.Println("5 seconds elapsed, client didn't close")
    case <-ctx.Done():
        fmt.Println("Context closed, client closed connection?")
        return
    }

    fmt.Fprint(w, "cancellation testing......")
})