Ошибка http.ErrServerClosed

Ошибка http.ErrServerClosed возвращается методом Server.ListenAndServe и аналогичными функциями, когда сервер был корректно остановлен с помощью метода Server.Shutdown. Эта ошибка не является критической и указывает на то, что сервер завершил работу по запросу, а не из-за сбоя. При корректной остановке сервера эту ошибку следует игнорировать, так как она является ожидаемым поведением.

Синтаксис

govar ErrServerClosed = errors.New("http: Server closed")

Пример

Давайте создадим HTTP-сервер и остановим его с помощью Shutdown с контекстом:

gopackage main

import (
  "context"
  "fmt"
  "log"
  "net/http"
  "time"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello, World!")
  })

  server := &http.Server{
    Addr:  ":8080",
    Handler: mux,
  }

  go func() {
    if err := server.ListenAndServe(); err != http.ErrServerClosed {
      log.Fatalf("Server error: %v", err)
    }
  }()

  // Wait for 5 seconds then shutdown
  time.Sleep(5 * time.Second)
  ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  defer cancel()

  if err := server.Shutdown(ctx); err != nil {
    log.Fatalf("Shutdown error: %v", err)
  }

  fmt.Println("Server gracefully stopped")
}

Результат выполнения кода:

go"Server gracefully stopped"

Пример

Давайте обработаем ошибку http.ErrServerClosed при запуске сервера в основной горутине:

gopackage main

import (
  "context"
  "log"
  "net/http"
  "os"
  "os/signal"
  "time"
)

func main() {
  server := &http.Server{
    Addr:  ":8080",
    Handler: http.DefaultServeMux,
  }

  // Handle shutdown signals
  idleConnsClosed := make(chan struct{})
  go func() {
    sigint := make(chan os.Signal, 1)
    signal.Notify(sigint, os.Interrupt)
    <-sigint

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    if err := server.Shutdown(ctx); err != nil {
      log.Printf("Shutdown error: %v", err)
    }
    close(idleConnsClosed)
  }()

  if err := server.ListenAndServe(); err != http.ErrServerClosed {
    log.Fatalf("Server error: %v", err)
  }

  <-idleConnsClosed
  log.Println("Server stopped")
}

Результат выполнения кода после отправки сигнала SIGINT:

go"Server stopped"

Смотрите также

  • функцию Server.Shutdown,
    которая корректно останавливает HTTP-сервер
  • функцию Server.ListenAndServe,
    которая запускает HTTP-сервер и ожидает подключений
  • функцию Server.Close,
    которая немедленно закрывает HTTP-сервер
  • функцию ErrHandlerTimeout,
    которая возникает при превышении времени обработки запроса