[Go] net/http routing

🧠·2022년 8월 30일
2

Go

목록 보기
1/5
post-thumbnail

Routing

Go 언어로 웹 서버를 구현하던 중 문득 라우팅을 어떻게 해주는지에 대해 궁금해졌다.

코드뚝딱 프로젝트를 진행할 때는 ExpressJS 프레임워크를 사용했고 라우팅 코드를 작성하는 경우 아래와 같이 작성하였다.

router.get('/javascript', function(...) {...});

최근 관심 있어 공부하게 된 Go 언어와 Gin 프레임워크로 웹 서버를 구현할 땐 라우팅 코드를 다음과 같이 작성하였다.

router.GET("/go", func(c *gin.Context) {...})

프레임워크를 사용하지 않을 땐 다음과 같이 해주었다. 프레임워크를 사용하지 않을 경우 Method를 구분하는 것은 직접 구현해야 했다.

http.HandleFunc("/go", func(w http.ResponseWriter ...) {...})

관련 자료를 찾아보기 전에 나의 생각은 이랬다.

들어온 요청 url path를 확인하여 /로 split 한 후 맵핑해주면 끝 아닌가?

결론부터 말하면 그것도 여러 방법 중 하나였다.

자료를 찾아본 결과 웹 프레임워크나 언어별로도 다른 로직으로 처리를 하고 있었다는 것을 알게 되었고 성능과 기능 또한 조금씩 다른 것으로 보였다.


Go net/http

Go의 net/http 라이브러리의 코드를 살펴보며 어떤 방식으로 라우팅을 하고 있는지 알아보았다.

먼저 http.HandleFunc("/go", func ...) 코드에서 HandleFunc는 pattern string 파라미터와 handler func 파라미터를 받는다.

HandleFunc 함수에서 handlernil이 아닐 때 Handle 함수를 호출하여 defaultServeMux에 파라미터로 받은 patternhandler를 muxEntry로 등록해 준다. (해당 함수 코드는 링크를 통해 확인할 수 있다.)

defaultServeMux의 타입은 ServeMux로 아래 첨부한 코드를 보면 구조체라는 것을 알 수 있다.

  • 코드를 자세히 보고 싶은 사람은 해당 링크로 들어가면 볼 수 있습니다.

HandleFunc 함수를 통해 등록을 마친 후 HTTP 요청이 들어오면 handler 함수 등 여러 함수를 거쳐 (해당 과정은 아직 이해를 못 했다) 등록해놓은 pattern과 요청이 들어온 path와 비교를 하여 handler를 알맞게 찾아주는 match 과정을 거친다. 해당 과정은 아래에서 볼 수 있다.

코드를 자세히 보고 싶은 사람은 해당 링크로 들어가면 볼 수 있습니다.

  1. 정확히 일치하는 pattern이 있는지 1차 확인 후
  2. 없다면 mux.es (아마도 Entry Set)를 for문으로 돌며 pattern이 path의 접두사인 entry가 있는지 찾는 과정을 거친다.
  3. 찾았다면 handler와 pattern을 리턴하며 없다면 nil과 빈 문자열을 리턴한다.

이때 mux.es은 위에 ServeMux 구조체를 선언할 때 주석으로 slice of entries sorted from longest to shortest. 라고 적어놓은 것을 볼 수 있는데 접두사인 pattern 중 가장 많이 일치하는 Entry를 반환하기 위해 긴 문자열부터 비교를 하는 것이다.

이때 mux.es에는 /로 끝나는 pattern만 등록이 된다.

example ) http.HandleFunc("/golang/", handler)

  • /golang/abcde 요청이 들어오면 /golang/ 패턴에 등록된 핸들러가 호출된다.

Reference

profile
: )

0개의 댓글