バックグラウンドでHTTPサーバを起動する

secondarykey 2024/02/10 09:13
secondarykey 2024/02/10 09:13

サーバをインスタンス化する

HTTPサーバを起動する場合、

http.ListenAndServe()

を利用しますが、HTTPサーバをバックグラウンドで実行したい場合、これではHTTPサーバをシャットダウンすることができません。

http.Serverインスタンスを利用する

http.ListenAndServe() は中身を見ればわかると思いますが、http.Serverインスタンスを作成しているだけなのでAddrとHandlerを設定して上げるだけで動作します。

var srv http.Server
srv.Addr = "localhost:8080"
srv.Handler = http.FileServer(http.FS(fs))
go func() {
  srv.ListenAndServe()
} ()
...
srv.Shutdown() //終了したい場合Shutdown()を呼ぶ

ポート番号を固定しない

ポート番号を0に設定すると空いているポートを発行してくれます。 ただ、上記のようにListenAndServe() ではその発行したポートを知ることができない為、どこにアクセスしていいかわからなくなります。 そういう場合はListen and Serve ではなく個別にListen とServeを行います。

net.Listen() を利用して一旦net.Listenerを生成しておいて、Addr() で知ることができます。

ln, err := net.Listen("tcp", "127.0.0.1:0")
fmt.Println(ln.Addr().String())
err = server.Serve(ln)

http.Server.Serve()の戻り値

忘れがちですがListenAndServe() もそうですが、起動できなかった場合などにerrorを返してくれてます。 Server.Shutdown() を利用するとServe()はerrorを返して終了する為、 起動した時にしっかりエラー処理を行っていると注意が必要です。

自分でShutdown() を行ったらフラグなどを利用して、http.ErrServerClosedを判定する必要があります。

err := srv.Serve(ln)
if err != nil {
  if isShutdown() && errors.Is(err,http.ErrServerClosed) {
    //無視
  }
}

アドレスとポートを連結する

よくアドレスを作成する時に

addr := fmt.Sprintf("%s:%d",host,port)

※IPv6時にHostを”[]"でくくってくれます。

を行いますが、IPv6時に動作しません。 net.JoinHostPort() を利用しておくと安全です。

net.JoinHostPort(host, strconv.Itoa(port))

The Go gopher was designed by Renee French.

The design is licensed under the Creative Commons 3.0 Attributions license. Read this article for more details:

vertical_align_top