如何在Go中处理完一次请求后停止HTTP服务?
嘿,这个需求太常见了——做OAuth或者第三方认证的时候,经常需要临时开个本地端口收回调token,用完就关。我给你两种实用的Go实现方式,看你偏好哪种:
方法一:优雅关闭服务(推荐)
这种方式会等当前请求完全处理完再终止服务,不会出现token还没拿到就中断的情况,非常稳妥。
package main import ( "context" "fmt" "net/http" "sync" ) func main() { // 用WaitGroup确保请求处理完成后再关服务 var wg sync.WaitGroup wg.Add(1) mux := http.NewServeMux() mux.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) { defer wg.Done() // 这里处理你的token逻辑,比如从URL参数里取 token := r.URL.Query().Get("token") fmt.Printf("成功拿到Token:%s\n", token) w.Write([]byte("认证完成!这个页面可以关闭了")) // 启动goroutine关闭服务,避免阻塞当前请求 go func() { wg.Wait() if err := server.Shutdown(context.Background()); err != nil { fmt.Printf("关闭服务时出错:%v\n", err) } }() }) server := &http.Server{ Addr: ":8080", Handler: mux, } fmt.Println("临时服务启动,监听localhost:8080...") // ListenAndServe会阻塞直到服务被Shutdown if err := server.ListenAndServe(); err != http.ErrServerClosed { fmt.Printf("服务意外终止:%v\n", err) } fmt.Println("服务已正常关闭") }
关键点说明:
sync.WaitGroup用来等待回调请求处理完毕,确保我们拿到token后再关服务- 必须在goroutine里调用
Shutdown,不然当前请求会被阻塞,客户端收不到响应 Shutdown会优雅关闭所有连接,不会强制中断正在处理的请求
方法二:快速终止服务(简洁版)
如果你的场景明确只需要处理一次请求,不需要考虑优雅关闭,这种方式更简单直接。
package main import ( "fmt" "net" "net/http" ) func main() { mux := http.NewServeMux() var listener net.Listener mux.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) { // 提取并处理token token := r.URL.Query().Get("token") fmt.Printf("Token已获取:%s\n", token) w.Write([]byte("认证成功!")) // 直接关闭监听,服务立刻停止 if listener != nil { if err := listener.Close(); err != nil { fmt.Printf("关闭监听失败:%v\n", err) } } }) var err error // 手动创建Listener,这样能拿到引用用来关闭 listener, err = net.Listen("tcp", ":8080") if err != nil { fmt.Printf("监听端口失败:%v\n", err) return } fmt.Println("等待第三方回调...") // Serve会一直运行直到Listener被关闭 if err := http.Serve(listener, mux); err != nil && err != http.ErrServerClosed { fmt.Printf("服务异常终止:%v\n", err) } fmt.Println("服务已停止") }
关键点说明:
- 手动创建
net.Listener代替ListenAndServe,这样我们能主动关闭它 - 在回调handler里调用
listener.Close(),http.Serve会立刻返回,服务终止 - 这种方式会直接断开所有连接,适合明确只处理一次请求的场景
额外注意事项:
- 确保第三方服务的回调地址和你代码里的一致(比如
http://localhost:8080/callback) - 如果是OAuth认证,回调路径要和你在第三方平台配置的完全匹配
- 第一种方法更通用,哪怕出现意外多请求也不会出问题;第二种方法更轻量,适合简单场景
内容的提问来源于stack exchange,提问作者Jonas
相关产品推荐
相关产品推荐

