golang 服务器中间件请求取消
golang server middlerware request cancellation
我在底部的示例中创建了一个小服务器,它位于 运行 端口 3000 上。您可以通过 "htto://localhost:3000/time" 访问它。整个 Request 被两个中间件覆盖。第一个 "cancelHandler" 和第二个 "otherHandler" 被调用 - 它在 4 秒后响应一些虚拟数据。
我的问题: 当我在浏览器中请求页面然后取消请求时(在 4 秒之前)。服务器仍在后台处理 goroutine/request。我已经花了几个小时在 google 上找到解决方案,但我无法理解上下文。 (context.WithCancel()) 我知道我必须创建一个 chan 并收听它,但这如何处理请求。那已经是一个 goroutine,我是否必须在 request/goroutine 中创建另一个 goroutine?另外一个问题是,我真的应该为此使用 Context 还是使用 cancelNotifier 有更简单的解决方案?
也许有人可以为我和其他可能有相同理解问题的人描述一下。
解决方案应该是取消处理程序在浏览器取消请求时停止 goroutine/request。
非常感谢您的宝贵时间!
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)
}
"stop" 一个函数的唯一方法是从它 return。因此,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
.
我在底部的示例中创建了一个小服务器,它位于 运行 端口 3000 上。您可以通过 "htto://localhost:3000/time" 访问它。整个 Request 被两个中间件覆盖。第一个 "cancelHandler" 和第二个 "otherHandler" 被调用 - 它在 4 秒后响应一些虚拟数据。
我的问题: 当我在浏览器中请求页面然后取消请求时(在 4 秒之前)。服务器仍在后台处理 goroutine/request。我已经花了几个小时在 google 上找到解决方案,但我无法理解上下文。 (context.WithCancel()) 我知道我必须创建一个 chan 并收听它,但这如何处理请求。那已经是一个 goroutine,我是否必须在 request/goroutine 中创建另一个 goroutine?另外一个问题是,我真的应该为此使用 Context 还是使用 cancelNotifier 有更简单的解决方案?
也许有人可以为我和其他可能有相同理解问题的人描述一下。
解决方案应该是取消处理程序在浏览器取消请求时停止 goroutine/request。
非常感谢您的宝贵时间!
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)
}
"stop" 一个函数的唯一方法是从它 return。因此,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
.