如何在收到参数后安全关闭 Golang 服务 - 最佳实践

3

我一直在使用golang实现服务器。当收到预期参数'code'后,我需要关闭服务器。在关闭服务器之前,我需要重定向到另一个网页。我已经按照以下方式实施了这个问题。这段代码能够工作,但是我想知道这是否是最佳实践?欢迎您提供建议。

func main() {
    var code string
    const port  int = 8888
    httpPortString := ":" + strconv.Itoa(port)
    mux := http.NewServeMux()
    fmt.Printf("Http Server initialized on Port %s", httpPortString)
    server := http.Server{Addr: httpPortString, Handler: mux}
    var timer *time.Timer
    mux.HandleFunc("/auth", func(w http.ResponseWriter, r *http.Request) {
        err := r.ParseForm()
        if err != nil {
            fmt.Printf("Error parsing the code: %s", err)
        }
        code = r.Form.Get("code")
        if err != nil {
            log.Printf("Error occurred while establishing the server: %s", err)
        }
        http.Redirect(w, r, "https://cloud.google.com/sdk/auth_success", http.StatusMovedPermanently)

        timer = time.NewTimer(2 * time.Second)
        go func() {
            <-timer.C
            server.Shutdown(context.Background())
        }()
    })
    if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
        fmt.Printf("Error while establishing the service: %s", err)
    }
    fmt.Println("Finished executing the the service")

}

谢谢你..!

1
无需休眠。在 http.Redirect 返回后,响应已经被写入并最终会到达客户端(假设没有网络故障)。 - Peter
1
谢谢回复。问题在于,如果我不让请求休眠,服务器会在重定向之前关闭。因此,我不得不添加计时器。我需要知道是否有更好的方法来完成这个任务,因为我感觉这不是最佳方式。 - Tharindu
1
@Tharindu 我也遇到了类似的情况。这是一个鸡生蛋的问题。HTTP响应只有在处理函数返回时才会刷新到客户端 - 因此,在处理程序内部关闭服务器意味着没有确定性的方法来确保其中一个发生在另一个之前。是的,sleep“可以” - 但我们知道这并不是一个保证。 - colm.anseo
啊,是的,我忘记了自动刷新。如果在关闭服务器之前调用w.Flush(需要类型断言),会发生什么?那样行得通吗? - Peter
@Peter在所有情况下都足够刷新吗? 在这种情况下,它是一个带有301状态代码的重定向。但是,如果没有设置状态,并且期望写入一个隐式的200状态代码头,会发生什么?刷写会触发该机制吗?我认为必须首先显式编写200标头。 - colm.anseo
显示剩余3条评论
1个回答

1

根据 @Peter 的建议和来自此处引用的示例的想法:

f, ok := w.(http.Flusher)
if !ok {
    http.Error(w, "no flush support", http.StatusInternalServerError)
    return
}   

http.Redirect(w, r, "https://cloud.google.com/sdk/auth_success", http.StatusSeeOther)

f.Flush() // <-- ensures client gets all writes
          // this is done implicitly on http handler returns, but...
          // we're shutting down the server now!

go func() {
    server.Shutdown(context.Background())
    close(idleConnsClosed)
}()

查看完整的 playground 版本,了解 idleConnsClosed 的设置和清理:https://play.golang.org/p/UBmLfyhKT0B


附注:除非您真的希望用户永远不再使用源URL,否则请勿使用http.StatusMovedPermanently。用户的浏览器将缓存此(301)代码 - 而不会访问您的服务器 - 这可能不是您想要的。如果您想要临时重定向,请使用http.StatusSeeOther(代码303)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接