Open robert-min opened 1 year ago
type appConfig struct {
logger *log.Logger
}
type app struct {
config appConfig
handler func(w http.ResponseWriter, r *http.Request, confing appConfig)
}
// 공통된 객체를 공유하는 핸들러 생성
func (a app) ServeHTTP(w http.ResponseWriter, r *http.Request) {
a.handler(w, r, a.config)
}
func apiHandler(w http.ResponseWriter, r *http.Request, config appConfig) {
config.logger.Println("Handling API request")
fmt.Fprintln(w, "Hello, world!")
}
func healthCheckHandler(w http.ResponseWriter, r *http.Request, config appConfig) {
if r.Method != "GET" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
config.logger.Println("Handling healthcheck request")
fmt.Fprintf(w, "ok")
}
func setupHandler(mux *http.ServeMux, config appConfig) {
mux.Handle("/healthz", &app{config: config, handler: healthCheckHandler})
mux.Handle("/api", &app{config: config, handler: apiHandler})
}
func main() {
listenAddr := os.Getenv("LISTENADDR")
if len(listenAddr) == 0 {
listenAddr = ":8080"
}
config := appConfig{
logger: log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile),
}
mux := http.NewServeMux()
setupHandler(mux, config)
log.Fatal(http.ListenAndServe(listenAddr, mux))
}
type appConfig struct {
logger *log.Logger
}
type app struct {
config appConfig
handler func(w http.ResponseWriter, r *http.Request, config appConfig)
}
func (a app) ServeHTTP(w http.ResponseWriter, r *http.Request) {
a.handler(w, r, a.config)
}
func healthCheckHandler(w http.ResponseWriter, r *http.Request, config appConfig) {
if r.Method != "GET" {
config.logger.Printf("error=\"Invalid request\" path=%s method=%s", r.URL.Path, r.Method)
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
fmt.Fprintf(w, "ok")
}
func apiHandler(w http.ResponseWriter, r *http.Request, config appConfig) {
fmt.Fprintf(w, "Hello, World")
}
func panicHandler(w http.ResponseWriter, r *http.Request, config appConfig) {
panic("I panicked")
}
func setupHandlers(mux *http.ServeMux, config appConfig) {
mux.Handle("/healthz", &app{config: config, handler: healthCheckHandler})
mux.Handle("/api", &app{config: config, handler: apiHandler})
mux.Handle("/panic", &app{config: config, handler: panicHandler})
}
func loggingMiddleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
startTime := time.Now()
h.ServeHTTP(w, r)
log.Printf("protocol=%s path=%s method=%s duration=%f", r.Proto, r.URL.Path, r.Method, time.Now().Sub(startTime).Seconds())
})
}
func panicMiddleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rValue := recover(); rValue != nil {
log.Println("panic detected when handling request", rValue)
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Unexpected server error occured")
}
}()
h.ServeHTTP(w, r)
})
}
func main() {
listenAddr := os.Getenv("LISTEN_ADDR")
if len(listenAddr) == 0 {
listenAddr = ":8080"
}
config := appConfig{
logger: log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile),
}
mux := http.NewServeMux()
setupHandlers(mux, config)
m := loggingMiddleware(panicMiddleware(mux))
log.Fatal(http.ListenAndServe(listenAddr, m))
}
핸들러 함수 간에 객체(데이터 공유)