Go에서 웹페이지를 만드는 방법은 여러가지가 있습니다. 각 단계별로 형태가 바뀌면서 새로운 함수들과 구조가 나오는데, 여기서 생긴 궁금증을 정리하고 해소하기 위해 글로 남깁니다.
Go를 이용해 웹페이지를 만들려고 하면 가장 처음 만나는 코드는 다음과 같다. 가장 기본적인 형태로 HandleFunc 와 ListenAndServe 메소드를 사용한다.
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World!")
})
http.ListenAndServe(":3000", nil)
}
그런데 여기서 조금 변형하면 아래처럼 쓸 수 있다.
package main
import (
"fmt"
"net/http"
)
type fooHandler struct{}
func (f *fooHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World!")
}
func main() {
http.Handle("/", &fooHandler{})
http.ListenAndServe(":3000", nil)
}
ServeHTTP 를 사용해서 fooHandler 구조체의 메소드로 만들고 main 함수 내에서 HandleFunc가 아닌Handle 을 이용해 인스턴스를 불러온다.
여기서의 궁금증은 다음과 같다.
HandleFunc 와Handle 의 차이점은 무엇인지?ListenAndServe의 2번째 인자로 nil이 들어가는 이유는 무엇인지?

공식문서를 살펴보면 두 번째로 받는 인자가 다르다. HandleFunc 에선 안에 있던 handler 함수가 Handle 에선 밖에 있다. 단순히 함수가 안에 같이 포함되어 있냐 밖에 있냐 차이다. 예시에선 구조체를 만들어서 메소드를 가져오는 형태다.
별거 아닌 것 같지만 이러한 궁금증을 갖고 하나씩 찾아보는 것이 나중에 실력으로 쌓인다고 생각한다.

The handler is typically nil, in which case the
DefaultServeMuxis used.
기본적으로 nil을 사용하는데, 이 때 DefaultServeMux가 사용된다고 한다. nil을 적으면 DefaultServeMux를 기본값으로 가져오도록 하겠다는 얘기. DefaultServeMux 는 ServeMux의 기본값이라고 생각하면 되는데, 이 ServeMux는 HTTP 요청을 받는 멀티플렉서이다.(Mux가 멀티플렉서의 줄임말)
멀티플렉서는 URL 경로를 동시에 여러 개를 처리한다고 하여 멀티플렉서라 부른다. 즉, 여러 경로로 들어오는 요청에 적절한 핸들러를 매칭 시키는 역할을 한다. 이해를 돕기 위해 Handle 의 소스코드를 살펴보자.
func Handle(pattern string, handler Handler) {
DefaultServeMux.Handle(pattern, handler)
}
Handle 은 위에서 살펴봤듯이 경로와 핸들러 함수를 받는 함수다. DefaultServeMux에 경로와 핸들러를 전달한다. 즉, Handle 은 DefaultServeMux에 경로와 핸들러를 등록하는 함수라고 할 수 있다.
정리하자면 ServeMux는 여러 HTTP 경로를 요청값으로 받는 멀티플렉서이며, ServeMux의 기본값이 DefaultServeMux이다. 따라서 ListenAndServe의 2번째 인자로 nil을 적으면 DefaultServeMux를 통해 요청 받은 HTTP 경로를 적절한 핸들러와 매칭 시켜주는 것이다.
멀티플렉서를 도입한 코드는 다음과 같다.
package main
import (
"fmt"
"net/http"
)
type fooHandler struct{}
func (f *fooHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World!")
}
func main() {
mux := http.NewServeMux()
mux.Handle("/", &fooHandler{})
mux.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello bar!")
})
http.ListenAndServe(":3000", mux)
}
http.NewServeMux()를 이용해 새로운 멀티플렉서를 mux 변수에 담고, 각 핸들을 연결시킨 다음 ListenAndServe 두 번째 인자로 넣어주면 끝.