2017-07-07 104 views
1

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

为了测试我创建了下面的代码,我不知道,如果是这样做,因为我不得不创建HandleFuncgoroutine内的channel来处理请求的正确方式,把这个所有一起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(ch chan struct{}) { 
     time.Sleep(5 * time.Second) 
     fmt.Fprintln(w, "Hello") 
     ch <- struct{}{} 
    }(ch) 

    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 + Ç,这将是loged:

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

这工作BU牛逼想知道如果这模式(够程和选择)应在每一个嵌套处理程序使用,或者如果有正在实施的更好的方法。:

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

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

回答

1

在谷歌,我们需要去程序员通过上下文参数作为传入和传出请求之间呼叫路径上每个函数的第一个参数。

- Go Concurrency Patterns: Context

+0

您通过上下文,但是你还需要创建'选择{ 情况下<-ch: 情况下<-ctx.Done(): ERR:= ctx.Err () log.Println(err) http.Error(w,err.Error(),http.StatusPartialContent) }'?或者当客户断开连接时应如何处理? – nbari

+0

我读它作为每个异步过程需要比赛的情况下提前退出。无论如何,在严重的应用程序中,您可能需要超时的子环境 – AJcodez

+0

可以请你分享一个例子或者写一个基本的实现,基本上想知道这个处理器的所有代码是否在一个goruine中:'go func(ch chan struct {}){....' – nbari