2017-07-07 110 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