dongza1708 2018-02-22 11:02
浏览 153
已采纳

golang服务器中间件请求取消

I created in the example at the bottom a little server which is running on port 3000. You can access it over "htto://localhost:3000/time". The whole Request is covered with two middlewares. First "cancelHandler" and Second "otherHandler" is called - which is responding with some dummy data after 4 seconds.

To my problem: When i request the page in a browser and then cancel the request (before the 4sec). The server is still handling the goroutine/request in the background. I spent already hours to find a solution on google but i can just not wrap my head around the context. (context.WithCancel()) I get that i have to create a chan and listen to it but how does this work with the requests. thats already a goroutine, do i have to create another goroutine in the request/goroutine? Also another question is, should i really use Context for that or is there an easier solution with the cancelNotifier?

Maybe someone can describe it for me and others which maybe have the same understanding problem.

Solution should be that the cancel Handler is stopping the goroutine/request, when the browser cancels the request.

Thank you very much for your time!

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)
}
  • 写回答

1条回答 默认 最新

  • duanqian8867 2018-02-22 11:45
    关注

    The only way to "stop" a function is to return from it. Thus, time.Sleep cannot be interrupted. Use a select statement instead:

    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)
        }
    }
    

    In general, check the request context (or one that is derived from it) in strategic places. If the context is canceled, don't proceed any further and return.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置