서론
주소창에 www.naver.com
을 쳐서 들어가면 아래와 같이 네이버 홈페이지가 보인다.

이 포스팅에서는 주소창에 URL을 쳐서 들어갔을 때 어떤 과정을 통해 해당 사이트가 우리에게 보이는 것인지 알아보려고 한다.
결론부터 말하자면 이 과정은 아주 간단하다. 네이버의 웹서버에 너네 홈페이지 띄우고 싶은데 필요한 재료 좀 보내줘~ 하면 네이버 웹서버가 OK 하고 홈페이지를 띄우는 데에 필요한 재료를 보내 준다. 그러면 이 재료를 브라우저가 열심히 조리해서 띄워준다. 그러면 우리는 이제 네이버 웹사이트를 볼 수 있게 되는 것이다.
그럼 먼저, 네이버의 웹서버에 요청을 하는 과정을 알아보자.
1. DNS 서버로 IP 주소 알아내기
네이버의 웹 서버에 너네 홈페이지 재료 줘~! 하고 요청을 보내는 것이 바로 HTTP 요청이다. 그러면 이 요청을 어디로 보내는지는 어떻게 알 수 있을까? 이때 필요한 것이 바로 DNS 서버다.
내가 엄마한테 용돈을 보내달라고 전화를 걸고 싶은데, 엄마 이름만 알고 엄마 핸드폰 번호를 모르면 어떻게 될까? 정말 슬프게도 용돈을 받을 수 없을 것이다. 엄마 핸드폰 번호도 모르면서 텔레파시로 용돈 요청을 보낼 순 없으니까.
브라우저도 똑같다. HTTP 요청을 보내기 위해서는 IP 주소를 알아야만 한다. 우리는 지금 네이버의 이름(도메인 이름, www.naver.com)만 알고 서버 주소(IP 주소)를 모르는 상황이다. 하지만 다행히도 브라우저계의 114 같은 곳이 있는데, 바로 DNS 서버다. DNS 서버에 이름(=도메인 이름)에 해당하는 전화번호(=IP 주소) 알려줘~ 하면 DNS 서버는 IP 주소를 반환해준다. 그래서 우리는 이제 네이버의 IP 주소를 알 수 있다.
DNS 서버는 어떻게 IP 주소를 반환해 주는가?
1️⃣ 로컬 DNS 캐시에서 해당 도메인의 IP 주소가 저장되어 있는지 확인하기:
엄마한테 번호를 알아내려고 용돈이 필요할 때마다 114에 전화를 거는 건 미치게 비효율적인 짓이다. 따라서 나는 먼저 전화번호부를 뒤적거려 볼 것이다. 이 과정이 바로 로컬 DNS 캐시를 뒤적거리는 과정이다. 브라우저는 먼저 사용자의 컴퓨터에 저장되어 있는 로컬 DNS 캐시에서 해당 도메인의 IP 주소가 저장되어 있는지 확인해 본다.
윈도우에서는 ipconfig 명령어, Mac에서는 mDNSResponder 명령어를 통해 로컬 DNS 캐시를 확인할 수 있다.

이때, 만약 로컬 DNS 캐시에 저장된 IP 주소의 유효 시간(TTL)이 지나면 어쩔 수 없이 DNS 서버에 새로 요청을 보내야 한다.
만약 엄마의 전화번호가 저장되어 있지 않다면? 다음 과정으로 넘어간다.
2️⃣ OS, 라우터(공유기)에 저장되어 있는 캐시 확인하기:
나는 금쪽이니까 분명 최근에도 엄마한테 전화를 건 적이 있을 것이다. 그 기록을 보기 위해 최근 통화 목록을 먼저 찾아본다. 이 과정이 바로 OS 캐시를 확인하는 과정에 대응된다.
로컬 DNS 캐시에 IP 주소가 없다면, 운영체제가 관리하는 DNS 캐시를 확인한다. 이곳에서는 최근에 요청을 받아왔던 IP 주소들이 관리된다.
여기에도 없다면 네트워크의 라우터에서 DNS 캐시를 확인한다. 여기에도 IP 주소가 없다? 그러면 어쩔 수 없다. 이제는 114에 전화를 걸어야 하는 순간이다.
3️⃣ 설정된 로컬 DNS 서버로 요청 보내기:
ISP(인터넷 서비스 제공업체)가 사용하는 DNS 서버를 뒤적거린다. 예를 들어 나는 KT 인터넷을 사용하고 있는데, 이 경우에는 KT의 DNS 서버가 기본 DNS 서버로 설정되어 있다.
이 서버에 요청을 보냈는데, 여기서도 알지 못한다? 그러면 이제 마법의 문장이 시작된다. "담당자분께 문의해 볼게요."
4️⃣ 루트 네임서버 -> TLD 네임서버 -> 권한 네임서버로 요청 넘기기:
최상위 도메인을 관리하는 루트 네임서버에 요청을 보낸다. 여기서는 최상위 도메인(예: .com) 네임서버의 위치를 알려준다.
다음으로 TLD 네임서버는 naver.com과 같은 도메인을 관리하는 권한 네임서버를 알려준다.
이제 마지막으로 권한 네임서버에서 www.naver.com에 대한 정확한 IP 주소를 반환해 준다.
이 모든 과정을 통해 드디어 사용자가 입력했던 www.naver.com이라는 주소가 xxx.xxx.xxx.xxx 형태의 IP 주소로 변환되었다.
2. 알아낸 IP 주소로 접속
이제 IP 주소를 통해 브라우저가 해당 웹 서버와 아래와 같은 3-way handshake 과정을 거치며 TCP 연결을 수립한다.
1. 클라이언트가 서버에게 SYN 패킷을 보내며 똑똑~ 연결 가능? 하고 묻기: SYN 패킷은 "나 너랑 연결하고 싶어"라는 의미다.
2. 연결 가능하다면 서버에서 SYN + ACK 패킷을 보내며 "응~ 연결 가능~(ACK), 나도 연결하고 싶어~(SYN)"라고 응답한다.
3. 클라이언트가 다시 서버에게 "ㅇㅇ 연결 가능! ㄱㄱ"라는 의미의 ACK 패킷을 보낸다.
마침내 서버와 연결이 수립되었다. 이제 HTTP 요청을 통해 서버에서 데이터를 주고받을 수 있다.
3. HTTP/HTTPS 요청
이제 서버에게 URL에 들어가면 띄워줘야 하는 리소스(HTML, CSS, JS) 파일을 달라고 아래와 같이 HTTP/HTTPS 요청을 보낸다.

그리고 서버가 응답으로 HTML 문서를 보내준다.

미리 보기를 보면 이렇게 날 것의 페이지가 보이는데, 이는 서버가 응답해 준 것이 기본 골격이 되는 HTML이기 때문이다. 브라우저는 이제 이 HTML을 읽으면서 추가적인 리소스를 요청하고, 렌더링 과정을 거쳐야 한다.
4. HTML 리소스 다운로드
브라우저는 서버가 보내준 HTML을 분석한다. 이 중에 추가적인 재료가 필요한 게 있는지 파싱해야 한다. 필요한 추가 리소스가 있다면, 해당 리소스의 주소에 또 요청을 보내야 한다. 이 과정을 반복하여 필요한 모든 리소스가 정상적으로 다운받아졌다면, 이제 재료를 조합해 요리를 해서 사용자에게 건네주기만 하면 된다.
naver.com에 요청을 보냈을 때 응답으로 오는 HTML에는 아래와 같은 다양한 리소스가 포함되어 있다.


이 밖에도 겁나 많은 리소스가 있는데, 이 리소스를 모두 받아와야 초기 HTML 응답으로 받아온 날 것의 페이지가 우리가 아는 그 네이버 사이트로 변신하게 되는 것이다. 예를 들어, 첫 번째 줄의 "/favicon.ico?1"에 추가 요청을 보내서, 아래와 같은 favicon을 받아와야 한다.

그러면 날 것의 페이지에서 파비콘이 추가된 날 것의 페이지가 된다.
sp_autocomplete_241121.css와 같은 css 파일도 받아온다.

ndp-loder.js와 같은 js 파일도 받아온다.

이때, 추가 요청을 뒤적거리다 보면 어떤 리소스는 요청하지 않는 것을 발견할 수 있다. 분명 html만 보면 nFavicon96.png도 받아와야 할 것 같고, mma_204243574.png도 받아와야 할 것 같은데,

이렇게 불러오지 않는 경우도 있다. 브라우저는 HTML에 있는 모든 리소스를 요청하지는 않는다. 아니 필요한 모든 리소스 받아온다는 거 아니었어??? 모든 리소스 불러온다며??


필요한이 핵심이다. 지금 필요한 리소스만 받아온다. 브라우저가 이미 캐싱해 둬서 지금 요청을 보낼 필요가 없다면 요청을 보내지 않는다. 미디어 쿼리 조건에 부합하지 않아서 리소스를 받아올 필요가 없을 때도 받아오지 않는다. 브라우저가 보기에 사용자의 UI에 해당 리소스가 필요 없다고 여겨지면 그때도 해당 리소스를 받아오지 않는다.
이렇게 초기에 불러온 HTML을 가지고 DOM 트리도 만들고, CSSOM 트리도 만들면서, 병렬적으로 필요한 추가 리소스도 받아왔다면, 이제 이 모든 것을 잘 요리해서 사용자의 화면에 렌더링 해줘야 한다.
5. 렌더링
렌더링은 재료를 통해 요리를 하고 사용자에게 제공해 주는 모든 과정을 말한다. 이 과정은 다음과 같은 순서로 진행된다.
- Parsing: HTML 파싱 해서 DOM 트리, CSS 파일 파싱해서 CSSOM 트리를 만든다.
- Style: 두 트리를 결합해 렌더 트리를 만든다. 이때, 렌더트리는 화면에 표시될 요소들만을 포함한다.
- Layout: 렌더 트리에서 각 노드의 위치와 크기를 계산한다.
- Paint: 각 요소가 픽셀로 렌더링 된다.
- Composite: 생성된 여러 레이어를 합성해 최종 화면을 구성한다.
* 여기서 파싱은 4. HTML 리소스 다운로드 과정에서 함께 일어난다.
요약
구구절절 길게 설명해 두었지만 핵심만 간단히 요약하자면 다음과 같다.
- DNS 서버 이용해서 도메인 이름으로 IP 주소 찾기
- IP 주소로 서버와 TCP 연결 수립하기
- 서버에 요청 보내서 HTML 받아오기
- HTML 파싱하고 추가 리소스 받아오고 렌더링 하기
이렇게 주소창에 www.naver.com을 쳤을 때 일어나는 일에 대해 알아봤다. 내게 홈페이지 보여주려고 분주한 브라우저와 서버에게 감사를 전하며 이만 마치겠다.
서론
주소창에 www.naver.com
을 쳐서 들어가면 아래와 같이 네이버 홈페이지가 보인다.

이 포스팅에서는 주소창에 URL을 쳐서 들어갔을 때 어떤 과정을 통해 해당 사이트가 우리에게 보이는 것인지 알아보려고 한다.
결론부터 말하자면 이 과정은 아주 간단하다. 네이버의 웹서버에 너네 홈페이지 띄우고 싶은데 필요한 재료 좀 보내줘~ 하면 네이버 웹서버가 OK 하고 홈페이지를 띄우는 데에 필요한 재료를 보내 준다. 그러면 이 재료를 브라우저가 열심히 조리해서 띄워준다. 그러면 우리는 이제 네이버 웹사이트를 볼 수 있게 되는 것이다.
그럼 먼저, 네이버의 웹서버에 요청을 하는 과정을 알아보자.
1. DNS 서버로 IP 주소 알아내기
네이버의 웹 서버에 너네 홈페이지 재료 줘~! 하고 요청을 보내는 것이 바로 HTTP 요청이다. 그러면 이 요청을 어디로 보내는지는 어떻게 알 수 있을까? 이때 필요한 것이 바로 DNS 서버다.
내가 엄마한테 용돈을 보내달라고 전화를 걸고 싶은데, 엄마 이름만 알고 엄마 핸드폰 번호를 모르면 어떻게 될까? 정말 슬프게도 용돈을 받을 수 없을 것이다. 엄마 핸드폰 번호도 모르면서 텔레파시로 용돈 요청을 보낼 순 없으니까.
브라우저도 똑같다. HTTP 요청을 보내기 위해서는 IP 주소를 알아야만 한다. 우리는 지금 네이버의 이름(도메인 이름, www.naver.com)만 알고 서버 주소(IP 주소)를 모르는 상황이다. 하지만 다행히도 브라우저계의 114 같은 곳이 있는데, 바로 DNS 서버다. DNS 서버에 이름(=도메인 이름)에 해당하는 전화번호(=IP 주소) 알려줘~ 하면 DNS 서버는 IP 주소를 반환해준다. 그래서 우리는 이제 네이버의 IP 주소를 알 수 있다.
DNS 서버는 어떻게 IP 주소를 반환해 주는가?
1️⃣ 로컬 DNS 캐시에서 해당 도메인의 IP 주소가 저장되어 있는지 확인하기:
엄마한테 번호를 알아내려고 용돈이 필요할 때마다 114에 전화를 거는 건 미치게 비효율적인 짓이다. 따라서 나는 먼저 전화번호부를 뒤적거려 볼 것이다. 이 과정이 바로 로컬 DNS 캐시를 뒤적거리는 과정이다. 브라우저는 먼저 사용자의 컴퓨터에 저장되어 있는 로컬 DNS 캐시에서 해당 도메인의 IP 주소가 저장되어 있는지 확인해 본다.
윈도우에서는 ipconfig 명령어, Mac에서는 mDNSResponder 명령어를 통해 로컬 DNS 캐시를 확인할 수 있다.

이때, 만약 로컬 DNS 캐시에 저장된 IP 주소의 유효 시간(TTL)이 지나면 어쩔 수 없이 DNS 서버에 새로 요청을 보내야 한다.
만약 엄마의 전화번호가 저장되어 있지 않다면? 다음 과정으로 넘어간다.
2️⃣ OS, 라우터(공유기)에 저장되어 있는 캐시 확인하기:
나는 금쪽이니까 분명 최근에도 엄마한테 전화를 건 적이 있을 것이다. 그 기록을 보기 위해 최근 통화 목록을 먼저 찾아본다. 이 과정이 바로 OS 캐시를 확인하는 과정에 대응된다.
로컬 DNS 캐시에 IP 주소가 없다면, 운영체제가 관리하는 DNS 캐시를 확인한다. 이곳에서는 최근에 요청을 받아왔던 IP 주소들이 관리된다.
여기에도 없다면 네트워크의 라우터에서 DNS 캐시를 확인한다. 여기에도 IP 주소가 없다? 그러면 어쩔 수 없다. 이제는 114에 전화를 걸어야 하는 순간이다.
3️⃣ 설정된 로컬 DNS 서버로 요청 보내기:
ISP(인터넷 서비스 제공업체)가 사용하는 DNS 서버를 뒤적거린다. 예를 들어 나는 KT 인터넷을 사용하고 있는데, 이 경우에는 KT의 DNS 서버가 기본 DNS 서버로 설정되어 있다.
이 서버에 요청을 보냈는데, 여기서도 알지 못한다? 그러면 이제 마법의 문장이 시작된다. "담당자분께 문의해 볼게요."
4️⃣ 루트 네임서버 -> TLD 네임서버 -> 권한 네임서버로 요청 넘기기:
최상위 도메인을 관리하는 루트 네임서버에 요청을 보낸다. 여기서는 최상위 도메인(예: .com) 네임서버의 위치를 알려준다.
다음으로 TLD 네임서버는 naver.com과 같은 도메인을 관리하는 권한 네임서버를 알려준다.
이제 마지막으로 권한 네임서버에서 www.naver.com에 대한 정확한 IP 주소를 반환해 준다.
이 모든 과정을 통해 드디어 사용자가 입력했던 www.naver.com이라는 주소가 xxx.xxx.xxx.xxx 형태의 IP 주소로 변환되었다.
2. 알아낸 IP 주소로 접속
이제 IP 주소를 통해 브라우저가 해당 웹 서버와 아래와 같은 3-way handshake 과정을 거치며 TCP 연결을 수립한다.
1. 클라이언트가 서버에게 SYN 패킷을 보내며 똑똑~ 연결 가능? 하고 묻기: SYN 패킷은 "나 너랑 연결하고 싶어"라는 의미다.
2. 연결 가능하다면 서버에서 SYN + ACK 패킷을 보내며 "응~ 연결 가능~(ACK), 나도 연결하고 싶어~(SYN)"라고 응답한다.
3. 클라이언트가 다시 서버에게 "ㅇㅇ 연결 가능! ㄱㄱ"라는 의미의 ACK 패킷을 보낸다.
마침내 서버와 연결이 수립되었다. 이제 HTTP 요청을 통해 서버에서 데이터를 주고받을 수 있다.
3. HTTP/HTTPS 요청
이제 서버에게 URL에 들어가면 띄워줘야 하는 리소스(HTML, CSS, JS) 파일을 달라고 아래와 같이 HTTP/HTTPS 요청을 보낸다.

그리고 서버가 응답으로 HTML 문서를 보내준다.

미리 보기를 보면 이렇게 날 것의 페이지가 보이는데, 이는 서버가 응답해 준 것이 기본 골격이 되는 HTML이기 때문이다. 브라우저는 이제 이 HTML을 읽으면서 추가적인 리소스를 요청하고, 렌더링 과정을 거쳐야 한다.
4. HTML 리소스 다운로드
브라우저는 서버가 보내준 HTML을 분석한다. 이 중에 추가적인 재료가 필요한 게 있는지 파싱해야 한다. 필요한 추가 리소스가 있다면, 해당 리소스의 주소에 또 요청을 보내야 한다. 이 과정을 반복하여 필요한 모든 리소스가 정상적으로 다운받아졌다면, 이제 재료를 조합해 요리를 해서 사용자에게 건네주기만 하면 된다.
naver.com에 요청을 보냈을 때 응답으로 오는 HTML에는 아래와 같은 다양한 리소스가 포함되어 있다.


이 밖에도 겁나 많은 리소스가 있는데, 이 리소스를 모두 받아와야 초기 HTML 응답으로 받아온 날 것의 페이지가 우리가 아는 그 네이버 사이트로 변신하게 되는 것이다. 예를 들어, 첫 번째 줄의 "/favicon.ico?1"에 추가 요청을 보내서, 아래와 같은 favicon을 받아와야 한다.

그러면 날 것의 페이지에서 파비콘이 추가된 날 것의 페이지가 된다.
sp_autocomplete_241121.css와 같은 css 파일도 받아온다.

ndp-loder.js와 같은 js 파일도 받아온다.

이때, 추가 요청을 뒤적거리다 보면 어떤 리소스는 요청하지 않는 것을 발견할 수 있다. 분명 html만 보면 nFavicon96.png도 받아와야 할 것 같고, mma_204243574.png도 받아와야 할 것 같은데,

이렇게 불러오지 않는 경우도 있다. 브라우저는 HTML에 있는 모든 리소스를 요청하지는 않는다. 아니 필요한 모든 리소스 받아온다는 거 아니었어??? 모든 리소스 불러온다며??


필요한이 핵심이다. 지금 필요한 리소스만 받아온다. 브라우저가 이미 캐싱해 둬서 지금 요청을 보낼 필요가 없다면 요청을 보내지 않는다. 미디어 쿼리 조건에 부합하지 않아서 리소스를 받아올 필요가 없을 때도 받아오지 않는다. 브라우저가 보기에 사용자의 UI에 해당 리소스가 필요 없다고 여겨지면 그때도 해당 리소스를 받아오지 않는다.
이렇게 초기에 불러온 HTML을 가지고 DOM 트리도 만들고, CSSOM 트리도 만들면서, 병렬적으로 필요한 추가 리소스도 받아왔다면, 이제 이 모든 것을 잘 요리해서 사용자의 화면에 렌더링 해줘야 한다.
5. 렌더링
렌더링은 재료를 통해 요리를 하고 사용자에게 제공해 주는 모든 과정을 말한다. 이 과정은 다음과 같은 순서로 진행된다.
- Parsing: HTML 파싱 해서 DOM 트리, CSS 파일 파싱해서 CSSOM 트리를 만든다.
- Style: 두 트리를 결합해 렌더 트리를 만든다. 이때, 렌더트리는 화면에 표시될 요소들만을 포함한다.
- Layout: 렌더 트리에서 각 노드의 위치와 크기를 계산한다.
- Paint: 각 요소가 픽셀로 렌더링 된다.
- Composite: 생성된 여러 레이어를 합성해 최종 화면을 구성한다.
* 여기서 파싱은 4. HTML 리소스 다운로드 과정에서 함께 일어난다.
요약
구구절절 길게 설명해 두었지만 핵심만 간단히 요약하자면 다음과 같다.
- DNS 서버 이용해서 도메인 이름으로 IP 주소 찾기
- IP 주소로 서버와 TCP 연결 수립하기
- 서버에 요청 보내서 HTML 받아오기
- HTML 파싱하고 추가 리소스 받아오고 렌더링 하기
이렇게 주소창에 www.naver.com을 쳤을 때 일어나는 일에 대해 알아봤다. 내게 홈페이지 보여주려고 분주한 브라우저와 서버에게 감사를 전하며 이만 마치겠다.