在 go 語言裡啟動一個 http 服務非常簡單,只需要一行代碼http.ListenAndServe()
就可以搞定,這個方法會一直阻塞著直到進程關閉,如果這個時候來了些特殊的需求比如:
在 go 中應該怎麼實現呢?下面來一一舉例。
將Listen
步驟拆分出來,先監聽埠,再綁定到server
上,代碼示例:
l, _ := net.Listen("tcp", ":8080")// 服務啟動成功,進行初始化doInit()// 綁定到server上http.Serve(l, nil)
通過一個協程
去輪詢監聽服務啟動狀態,代碼示例:
go func() { for { if _, err := net.Dial("tcp", "127.0.0.1:8080"); err == nil { // 服務啟動成功,進行初始化 doInit() //退出協程 break } // 每隔一秒檢查一次服務是否啟動成功 time.Sleep(time.Second) }}()http.ListenAndServe(":8080", nil)
在http
包中並沒有暴露服務的關閉方法,通過http.ListenAndServe()
方法啟動的 http 服務默認幫我們創建了一個*http.Server
對象,源碼如下:
func ListenAndServe(addr string, handler Handler) error { server := &Server{Addr: addr, Handler: handler} return server.ListenAndServe()}
實際上在*http.Server
中是有提供Shutdown
方法的,所以我們只需要手動構造一個*http.Server
對象,就可以進行優雅關閉了,代碼示例:
srv := &http.Server{Addr: ":8080"}go func(){ // 10秒之後關閉服務 time.Sleep(time.Second * 10) srv.Shutdown(context.TODO())}()// 啟動服務srv.ListenAndServe()
強制關閉和上面步驟是一樣的,只是調用的方法換成了srv.Close()
,這會導致所有的請求立即中斷,所以需要特別注意。
當我們手動將服務關閉之後,srv.ListenAndServe()
方法就會立即返回,這裡需要注意的是該方法會返回一個error
,當然這個error
是一個特殊的 error http.ErrServerClosed
,幫助我們區分是否為正常的服務關閉,所以需要對它特殊處理下,代碼示例:
if err := server.ListenAndServe(); err != nil { // 服務關閉,進行處理 doShutdown() if err != http.ErrServerClosed{ // 異常宕機,列印錯誤信息 log.Fatal(err) }}
本文首發於我的博客:,歡迎收藏!不定期分享
JAVA
、Golang
、前端
、docker
、k8s
等乾貨知識。