브라우저의 네비게이션 과정
![브라우저의 네비게이션 과정](/content/images/size/w1200/2023/07/0_ytMB6Lx8Z1Gy-xXl.jpg)
브라우저의 주소창에 URL을 입력하면 일어나는 일
목차
- 브라우저의 주소창에 URL을 입력한다.
- 브라우저가 요청한 URL의 IP 주소를 찾기 위해 캐시를 확인한다.
- (캐시에 요청한 주소가 없다면) ISP의 DNS 서버가 요청한 URL의 IP 주소를 검색한다.
- 브라우저가 서버와 TCP 연결을 시작한다.
- 브라우저가 서버에 HTTP 요청을 보낸다.
- 서버가 요청을 처리하고 브라우저에 HTTP 응답을 보낸다.
- 브라우저가 HTTP 응답을 읽어 다음 할 일을 결정한다.
- 브라우저가 HTML을 렌더링하고 브라우저의 상태를 업데이트한다.
1. 브라우저의 주소창에 URL을 입력한다.
크롬 브라우저의 경우 수많은 프로세스를 가지고 있는데, 대표적으로 브라우저 프로세스(Electron에선 메인 프로세스)와 렌더러 프로세스가 있고, 브라우저 프로세스의 하위에는 UI 스레드와 네트워크 스레드가 있다.
주소창에 URL을 입력하면, 브라우저 프로세스의 UI 스레드는 네트워크 호출을 위해 네트워크 스레드로 요청을 전달하고, 이 다음 작업은 계속 네트워크 스레드에 의해 처리된다.
2. 브라우저가 요청한 URL의 IP 주소를 찾기 위해 캐시를 확인한다.
DNS(Domain Name System)는 웹사이트의 IP 주소와 도메인 주소를 연결해주는 시스템으로, 쉽게 얘기하면 전화번호부와 같다. (이름과 전화번호를 연결)
모든 URL은 고유한 IP 주소가 연결되어 있는데, 예를 들어 www.google.com의 IP 주소는 142.250.207.100이다. 따라서 브라우저에서 https://142.250.207.100/ 을 입력하면 www.google.com에 접속할 수 있다.
IP 주소는 터미널에서 ‘nslookup’ 명령어로 확인할 수 있다. nslookup www.google.com
브라우저는 DNS 레코드를 찾기 위해 다음 순서로 캐시를 탐색하는데, 일단 브라우저 캐시, 다음은 OS 캐시를 탐색한다. 그럼에도 찾지 못했다면 라우터 캐시를, 다음은 ISP 캐시를 탐색한다.
라우터는 공유기 또는 비싸고 기능 많은 공유기 비슷한 것을 말하고,
ISP(Internet Service Provider)는 SK, KT, LG U+ 등, 인터넷 서비스를 제공하는 주체로, 브라우저는 이들이 가지고 있는 DNS 서버 캐시를 탐색한다.
사실 구글도 ISP에 속한다. 다만 가입자를 받지 않을 뿐. (Google Fiber라고 일부 지역에서 사업을 하고 있긴 하다)
이렇게 다양한 캐시를 가지고 있는 이유는, (대부분의 캐시가 비슷한 이유겠지만) 네트워크 트래픽을 줄이고 데이터 전송 시간을 개선하기 위함이라고 한다.
3. (캐시에 요청한 주소가 없다면) ISP의 DNS 서버가 요청한 URL의 IP 주소를 검색한다.
만약 캐시에서 DNS 레코드를 찾지 못했다면, 결국 검색을 해야 할 것이다. 이때 ISP의 DNS 서버는 DNS 쿼리를 시작해 IP 주소를 검색한다.
이때 검색 과정은 IP 주소를 찾거나, 오류를 반환할 때까지 여러 DNS를 반복적으로 탐색하는 Recursive query 방식이며, (완전 탐색?) 쿼리를 담당하는 이 녀석은 DNS 리커서(DNS Recursor)라고 한다.
도메인의 구조와 이를 검색하는 과정은 아래와 같다:
![](https://cdn-images-1.medium.com/max/800/0*TeCYNTkbcy_mKPQd.png)
DNS 리커서는 IP 주소를 찾는다면 브라우저에게 반환하고, 그렇지 못하면 오류를 반환한다.
4. 브라우저가 서버와 TCP 연결을 시작한다.
브라우저가 올바른 IP 주소를 수신하면 해당 주소의 서버와 연결해 정보를 전송한다. 이러한 통신은 인터넷 프로토콜(IP, Internet Protocol)을 통해 이루어지는데, 다양한 인터넷 프로토콜이 있지만 우리가 흔히 사용하는 HTTP(Hyper Text Transfer Protocol)는 TCP(Transmission Control Protocol)를 기반으로 한다.
둘 다 프로토콜인데 HTTP가 TCP를 사용한다는 게 무슨 말일까? 아래 모델에서 TCP는 전송 계층(Transport Layer), HTTP는 응용 계층(Application Layer)에 속한다.
HTTPS는 HTTP와 SSL/TLS의 합성어로, TCP가 속한 전송 계층에 TLS(Transport Layer Security, 전송 계층 보안) 프로토콜이 추가되어, 그 위에서 동작하는 HTTP 프로토콜이다. 통신 과정에서 정보가 탈취되는 것을 막기 위해 정보를 암호화해서 키와 함께 주고받는다.
그러므로 클라이언트(브라우저)와 서버와 간 데이터를 전송하려면 TCP 연결이 이루어져야 한다. 이때 연결은 3-Way Handshake, 종료는 4-Way Handshake라는 과정을 통해 이루어진다.
주고받는 패킷의 종류는 요청에 해당하는 SYN(Synchronization), 종료 요청에 해당하는 FIN(Finish, 응답에 해당하는 ACK(Acknowledgement), 세 가지다.
3-Way Handshake (연결 시작)
- 클라이언트 → 서버: SYN(시작 ㄱ) 전송
- 서버 → 클라이언트: ACK(ㅇㅋ)과 SYN(포트 여셈) 전송
- 클라이언트 → 서버: ACK(ㅇㅋ) 전송
4-Way Handshake (연결 종료)
- 클라이언트 → 서버: FIN(종료 ㄱ) 전송
- 서버 → 클라이언트: ACK(ㅇㅋ, ㄱㄷ) 전송
- 서버 → 클라이언트: 모든 통신을 마친 후 FIN(종료 ㄱ) 전송
- 클라이언트 → 서버: ACK(ㅇㅋ) 전송
잠깐 프로토콜에 관해 얘기하자면, HTTP는 Connectionless라는 말이 있다. HTTP는 TCP를 기반으로 하고 TCP는 Connection-Oriented인데 이게 무슨 말이지?
일단 Stateless 하다는 건 응답(Response)과 동시에 연결(Connection)이 끊어져 새로운 요청을 처리할 때 이전에 어떤 요청(Request)과 응답이 있었는지 알지 못한다는 뜻. 그리고 Connectionless는 이렇게 연결을 매번 끊고 새로 생성하는 방식을 말한다. 결국 하나의 요청과 응답 사이에는 TCP 특성상 연결이 유지되어 있지만, HTTP는 연결을 항상 끊어버리기 때문에 이런 말이 나오는 것.
하지만 HTTP/1.1 부터는 HTTP persistent connection을 공식 스펙(keep-alive)으로 지원한다. 가능하면 TCP 연결을 유지하고, 여러 HTTP 요청이 하나의 TCP 연결을 사용하도록 해 3-Way Handshake를 생략하는 게 기본값이다.
![](https://upload.wikimedia.org/wikipedia/commons/thumb/5/5b/HTTP_logo.svg/1200px-HTTP_logo.svg.png)
5. 브라우저가 서버에 HTTP 요청을 보낸다.
TCP 연결이 설정되면 이제 데이터 전송을 시작한다. 브라우저는 www.google.com 웹 페이지를 요청하는 GET HTTP 요청을 보낼 것이다.
![](https://cdn-images-1.medium.com/max/800/1*gFzQzGtaAx9zdptc2rqzJw.png)
6. 서버가 요청을 처리하고 브라우저에 HTTP 응답을 보낸다.
서버에는 Apache, Tomcat, IIS, NGINX 등의 웹 서버가 포함되어 있는데, 이는 브라우저로부터 요청을 수신하고, 이 요청을 처리할 핸들러에게 전달하고, 보내려는 응답을 읽어 JSON, HTML 등, 특정 타입의 포맷(MIME types)으로 작성하는 역할을 한다.
![](https://cdn-images-1.medium.com/max/800/1*iEbHR3vI98aFLB9RMo1utA.png)
General 패널에 보이겠지만 HTTP Status Code는 굉장히 다양한데, 만약 301 리디렉션 코드를 수신한다면 새로운 URL로 이동 후 이 과정들을 다시 거칠 것이다.
![](https://developer.mozilla.org/mdn-social-share.cd6c4a5a.png)
7. 브라우저가 HTTP 응답을 읽어 다음 할 일을 결정한다.
브라우저는 응답을 받으면 먼저 응답 페이로드(Payload)의 데이터 타입을 확인한다. 응답 헤더(Response Headers)의 Content-Type
이 페이로드의 데이터 타입(MIME types)을 알려 주지만, 정보가 없거나 잘못되었을 수 있다. 때문에 브라우저는 payload 스트림의 처음 몇 bytes를 확인해 Content-Type
헤더와 페이로드의 실제 데이터 타입이 일치하는지 확인한다. 이 과정은 보안과도 관련이 있다. (MIME Sniffing)
![](https://cdn-images-1.medium.com/max/800/0*Kqfe_f852yjkOu2k.png)
페이로드의 데이터 타입에 따라 브라우저는 다음 할 일을 결정하는데, 다운로드 가능한 타입(e.g. ZIP)이라면 다운로드를, 렌더링 가능한 타입(e.g. HTML, PDF)이라면 렌더링을 시작한다.
지금까지의 모든 과정은 브라우저 프로세스 내에서 이루어졌다. 이 중에서 1번과 6번의 리디렉션처럼, 브라우저의 UI에 영향을 주는 일은 UI 스레드, 이 외엔 모두 네트워크 스레드에서 처리되었다.
지금은 페이로드로 HTML을 받았으니 다음은 드디어 렌더링 프로세스에서 일이 처리될 것이다.
8. 브라우저가 HTML을 렌더링하고 브라우저의 상태를 업데이트한다.
이 시점에 UI 스레드는 로딩 스피너 표시, 주소창, 뒤로 가기와 앞으로 가기 버튼 등, 브라우저의 다양한 상태와 UI를 변경한다.
또한 브라우저 프로세스는 IPC(Inter-Process Communication) 채널을 통해 렌더러 프로세스에게 메시지를 보내면서 이 모든 과정의 목적인 렌더링도 시작되는데, UI 스레드는 렌더링을 요청하는 메시지(이벤트)를, 네트워크 스레드는 렌더링에 필요한 데이터 스트림을 지속해서 보낸다.
![](https://cdn-images-1.medium.com/max/800/0*Cs6q5pTkb2y1O6ok.png)
렌더러 프로세스 내부에서 발생하는 일은 이틀 전에 작성한 글로 대체한다. (다음 글은 크로미움에 국한되지 않아 렌더러 프로세스라는 용어를 사용하지 않는다)
![](https://www.choegyumin.com/content/images/2023/07/1_dNtyOMGLuKZpeLG0FLZchA.webp)
Page load가 완료되면, 렌더러 프로세스는 아까와 마찬가지로 IPC 채널을 통해 브라우저 프로세스에게 렌더링이 끝났음을 알린다. UI 스레드는 로딩 스피너를 중지하고 파비콘을 업데이트하는 등, 다시 한번 상태와 UI를 변경하고 과정이 마무리된다. (새로운 리소스 요청 전까지)
정리
- 브라우저의 주소창에 URL을 입력한다.
브라우저 프로세스의 UI 스레드는 네트워크 스레드에게 네트워크 호출을 요청한다. - 브라우저가 요청한 URL의 IP 주소를 찾기 위해 캐시를 확인한다.
브라우저 캐시, OS 캐시, 라우터 캐시, ISP 캐시 등. - (캐시에 요청한 주소가 없다면) ISP의 DNS 서버가 요청한 URL의 IP 주소를 검색한다.
검색 과정은 루트 도메인부터 하위 도메인까지 매칭되는 DNS를 완전 탐색한다. - 브라우저가 서버와 TCP 연결을 시작한다.
HTTP는 TCP를 기반으로 하며, HTTP/1.1부터는 HTTP persistent connection을 공식 스펙(keep-alive)으로 지원해 여러 HTTP 요청이 하나의 TCP 연결을 사용하도록 한다. (TCP 연결이 종료되는 조건이 있다) - 브라우저가 서버에 HTTP 요청을 보낸다.
- 서버가 요청을 처리하고 브라우저에 HTTP 응답을 보낸다.
Apache, IIS, NGINX 등의 웹 서버가 요청을 받아 이를 처리할 핸들러에게 보내고, 응답을 읽어 JSON, HTML 등의 MIME types 포맷으로 변환한다. - 브라우저가 HTTP 응답을 읽어 다음 할 일을 결정한다.
응답 페이로드의 데이터 타입이 응답 헤더의Content-Type
과 일치하는지 검증하고, 데이터 타입에 따라 다운로드나 렌더링 등 다음 할 일을 결정한다. - 브라우저가 HTML을 렌더링하고 브라우저의 상태를 업데이트한다.
UI 스레드는 렌더링 시작과 완료 시점에 로딩 스피너 표시, 파비콘, 주소창, 뒤로 가기와 앞으로 가기 버튼 등의 UI와 상태를 업데이트한다.
그리고 UI 스레드는 IPC(Inter-Process Communication) 채널을 통해 렌더링 요청을, 네트워크 스레드는 렌더링에 필요한 데이터 스트림을 렌더링 프로세스에게 보낸다.