如何使用带有嵌套http中间件的context.Done()

时间:2017-07-07 20:26:32

标签: http go

我想知道在context.Done()服务器中使用HTTP并实现middleware时如何正确实现/使用channel方法,我的目标是在客户端断开连接时取消后续事件跨嵌套中间件。

为了测试我创建了以下代码,我不知道这是否正确,因为我必须在HandleFunc和{{3}内创建goroutine处理请求,将所有这些放在select等待语句中。

package main

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

func hello(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()
    log.Println("handler started")
    defer log.Println("hander ended")

    ch := make(chan struct{})

    go func() {
        time.Sleep(5 * time.Second)
        fmt.Fprintln(w, "Hello")
        ch <- struct{}{}
    }()

    select {
    case <-ch:
    case <-ctx.Done():
        err := ctx.Err()
        log.Println(err)
        http.Error(w, err.Error(), http.StatusPartialContent)
    }
}

func main() {
    http.HandleFunc("/", hello)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

这里请求通过休眠5秒来模拟负载,然后打印Hello,但如果客户端取消请求,例如:

$ curl 0:8080

然后按 ctl + c ,这将是隐藏的:

2017/07/07 22:22:40 handler started
2017/07/07 22:22:42 context canceled
2017/07/07 22:22:42 hander ended

这有效,但想知道是否应该在每个嵌套处理程序中使用此模式(goroutine和select),或者是否有更好的方法来实现它。:

ch := make(chan struct{})
go func() {
    // some logic   
    ch <- struct{}{}
}()

select {
case <-ch:
case <-ctx.Done():
    err := ctx.Err()
    log.Println(err)
    http.Error(w, err.Error(), http.StatusPartialContent)
}

1 个答案:

答案 0 :(得分:1)

  

在Google,我们要求Go程序员将Context参数作为传入和传出请求之间的呼叫路径上的每个函数的第一个参数传递。

     

- Go Concurrency Patterns: Context