我在示例的底部创建了一个运行在端口3000上的小型服务器。您可以通过“ htto:// localhost:3000 / time”访问它。整个请求包含两个中间件。第一个“ cancelHandler”和第二个“ otherHandler”被调用-在4秒钟后响应一些虚拟数据。
对我的问题: 当我在浏览器中请求页面,然后取消请求时(在4秒之前)。服务器仍在后台处理goroutine /请求。我已经花了几个小时在Google上找到解决方案,但是我无法将自己的想法笼罩在上下文中。(context.WithCancel())我得到我必须创建一个chan并聆听它,但是这如何处理请求。那已经是一个goroutine,我是否必须在请求/ goroutine中创建另一个goroutine?另外一个问题是,我应该真的使用Context还是使用cancelNotifier来解决问题?
也许有人可以为我和其他有相同理解问题的人描述它。
解决方案应该是当浏览器取消请求时,取消处理程序将停止goroutine /请求。
非常感谢您的宝贵时间!
package main import ( "log" "net/http" "time" "fmt" ) func otherHandler(format string) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Duration(4)*time.Second) tm := time.Now().Format(format) w.Write([]byte("The time is: " + tm)) fmt.Println("response:", "The time is: "+tm) } return http.HandlerFunc(fn) } func cancelHandler(h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { fmt.Println("start: called cancelHandler") h.ServeHTTP(w, r) fmt.Println("end: called cancelHandler") } return http.HandlerFunc(fn) } func main() { mux := http.NewServeMux() th := otherHandler(time.RFC1123) mux.Handle("/time", cancelHandler(th)) log.Println("Listening...") http.ListenAndServe(":3000", mux) }
“停止”功能的唯一方法是从其返回。因此,time.Sleep无法中断。改用select语句:
package main import ( "fmt" "net/http" "time" ) func main() { http.ListenAndServe(":3000", otherHandler(time.RFC1123)) } func otherHandler(format string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { select { case <-time.After(4 * time.Second): // time's up case <-r.Context().Done(): // client gave up return } tm := time.Now().Format(format) w.Write([]byte("The time is: " + tm)) fmt.Println("response:", "The time is: "+tm) } }
通常,在战略位置检查请求上下文(或从中派生的请求上下文)。如果上下文已取消,则不要继续操作和return。
return