предисловие
Говорят, что стандартная библиотека go практична, а дизайн API прост. На этот раз я буду использовать пакет net/http из стандартной библиотеки go для реализации краткого веб-сервера http, включая три версии.
Самая простая версия v1
Используйте http.HandleFunc(partn, function(http.ResponseWriter,
*http.Request){})
HandleFunc принимает два параметра: первый — это адрес маршрутизации, а второй — метод обработки.
//v1
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("httpserver v1"))
})
http.HandleFunc("/bye", sayBye)
log.Println("Starting v1 server ...")
log.Fatal(http.ListenAndServe(":1210", nil))
}
func sayBye(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("bye bye ,this is v1 httpServer"))
}
Пользовательский обработчик v2
Глядя на исходный код стандартной библиотеки, версия v1 фактически вызывает метод handle, а входящий HandlerFunc реализует метод ServeHTTP обработчика, который на самом деле ServeHTTP выполняет обработку http-запроса.
Исходя из этого, мы можем настроить наш собственный обработчик.Код версии v2 выглядит следующим образом:
// v2
func main() {
mux := http.NewServeMux()
mux.Handle("/", &myHandler{})
mux.HandleFunc("/bye", sayBye)
log.Println("Starting v2 httpserver")
log.Fatal(http.ListenAndServe(":1210", mux))
}
type myHandler struct{}
func (*myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("this is version 2"))
}
func sayBye(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("bye bye ,this is v2 httpServer"))
}
Кастомная конфигурация сервера v3
Мы уже вонзали нож в Handler, давайте посмотрим, какие секреты скрыты в http.ListenAndServe().
Оказывается, здесь можно настроить конфигурацию http сервера, все в структуре Сервера.Этот объект может настроить порт адреса прослушивания, настроить таймаут чтения и записи, настроить обработчик, настроить максимальное количество байт в заголовке запроса ..., все они немного изменены v2 Программа получает версию v3:
// v3
func main() {
mux := http.NewServeMux()
mux.Handle("/", &myHandler{})
mux.HandleFunc("/bye", sayBye)
server := &http.Server{
Addr: ":1210",
WriteTimeout: time.Second * 3, //设置3秒的写超时
Handler: mux,
}
log.Println("Starting v3 httpserver")
log.Fatal(server.ListenAndServe())
}
type myHandler struct{}
func (*myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("this is version 3"))
}
func sayBye(w http.ResponseWriter, r *http.Request) {
// 睡眠4秒 上面配置了3秒写超时,所以访问 “/bye“路由会出现没有响应的现象
time.Sleep(4 * time.Second)
w.Write([]byte("bye bye ,this is v3 httpServer"))
}
Развернуть его (как плавно закрыть http сервис)
В версии go1.8 была добавлена новая функция, использующая Shutdown(ctx context.Context) для корректного закрытия службы http.
В документации описаны:
Завершение работы закроет активные соединения без прерывания работы, а затем корректно остановит службы. Процесс обработки выглядит следующим образом:
- Сначала закройте все слушатели;
- затем закройте все неиспользуемые соединения;
- Затем бесконечно ждать, пока соединение будет обработано, станет бездействующим и закроется;
- Если предоставляется контекст с тайм-аутом, ошибка тайм-аута контекста будет возвращена до закрытия службы;
Используйте эту функцию, чтобы преобразовать версию программы v3 для реализации запроса на закрытие http
// 主动关闭服务器
var server *http.Server
func main() {
// 一个通知退出的chan
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt)
mux := http.NewServeMux()
mux.Handle("/", &myHandler{})
mux.HandleFunc("/bye", sayBye)
server = &http.Server{
Addr: ":1210",
WriteTimeout: time.Second * 4,
Handler: mux,
}
go func() {
// 接收退出信号
<-quit
if err := server.Close(); err != nil {
log.Fatal("Close server:", err)
}
}()
log.Println("Starting v3 httpserver")
err := server.ListenAndServe()
if err != nil {
// 正常退出
if err == http.ErrServerClosed {
log.Fatal("Server closed under request")
} else {
log.Fatal("Server closed unexpected", err)
}
}
log.Fatal("Server exited")
}
type myHandler struct{}
func (*myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("this is version 3"))
}
// 关闭http
func sayBye(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("bye bye ,shutdown the server")) // 没有输出
err := server.Shutdown(nil)
if err != nil {
log.([]byte("shutdown the server err"))
}
}
Если вы попытаетесь получить доступ к http://localhost:1210/bye, вы получите следующие быстрые результаты в консоли, и служба http будет плавно закрыта: