golang服务器中间件请求取消

golang服务器中间件请求取消,go,server,middleware,Go,Server,Middleware,我在下面的示例中创建了一个运行在3000端口上的小型服务器。您可以通过“”访问它htto://localhost:3000/time". 整个请求包含两个中间程序。第一个“cancelHandler”和第二个“otherHandler”被调用-它在4秒后用一些虚拟数据进行响应 我的问题:当我在浏览器中请求页面,然后取消请求时(在4秒之前)。服务器仍在后台处理goroutine/请求。我已经花了好几个小时在谷歌上寻找解决方案,但我就是无法理解上下文。(context.WithCancel())我知

我在下面的示例中创建了一个运行在3000端口上的小型服务器。您可以通过“”访问它htto://localhost:3000/time". 整个请求包含两个中间程序。第一个“cancelHandler”和第二个“otherHandler”被调用-它在4秒后用一些虚拟数据进行响应

我的问题:当我在浏览器中请求页面,然后取消请求时(在4秒之前)。服务器仍在后台处理goroutine/请求。我已经花了好几个小时在谷歌上寻找解决方案,但我就是无法理解上下文。(context.WithCancel())我知道我必须创建一个chan并聆听它,但这如何处理请求。这已经是一个goroutine了,我必须在请求/goroutine中创建另一个goroutine吗?另外一个问题是,我真的应该使用上下文,还是使用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)
}
“停止”函数的唯一方法是从它返回。因此,时间。睡眠不能被打断。请改用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)
    }
}
主程序包
进口(
“fmt”
“net/http”
“时间”
)
func main(){
http.listendServe(“:3000”,otherHandler(time.RFC1123))
}
func otherHandler(格式字符串)http.HandlerFunc{
return func(w http.ResponseWriter,r*http.Request){
挑选{

案例,也许我应该提到,当客户端中断连接时,Go将为您取消上下文。您不需要上下文。使用cancel/Timeout/Deadline,除非您想添加自己的中止条件。首先感谢您的回答。我完全理解您的示例。但它还不能解决我的问题。如果我使用了而不是“time.After(4s)”是另一个处理主响应的处理程序,这是一个很重的负载。如果用户关闭浏览器,它仍然会运行至少一个完整的时间。因为我必须在select语句之前调用它。所以在select语句之前已经有了“heavyLoad”“正在处理函数或处理程序。在这之后是选择,如果浏览器关闭,这里将是逻辑……对我来说仍然没有100%的意义。唯一对我有意义的解决方案是,在另一个goroutine中调用“重载”函数。从goroutine获取进程ID(不知道这是否可能)。现在,Select将在goroutine被触发后立即运行,如果出现浏览器取消,go例程的过程必须停止。如果将上下文传递给heavyLoad,heavyLoad必须检查是否取消。如果没有heavyLoad的合作,您将无法通过。这也是一件好事。想象一下heavyLoad更新了一些数据库和n发送一封电子邮件,通知用户更新。在数据库更新后,即使客户端放弃,您也不想再中断更新。您不能“从外部”这样做。您是对的!谢谢您的帮助Pete;)