브라우저 작동원리2 - 페이지 이동
크롬 브라우저의 주소 표시줄에 URL을 입력하면 해당 페이지로 이동하게 된다. 이 과정에서 브라우저가 어떤 작업을 수행하는지 알아보자.
1. URL 입력
주소 표시줄에 URL을 입력하면 User Interface를 담당하는 브라우저 프로세스의 UI 스레드가 이를 감지하고 처리한다. 입력하는 도중에는 검색 기록에 기반하여 드롭다운 박스로 입력 값에 대한 제안을 주기도 한다. 입력 값에 대해 UI 스레드는 검색어인지 URL인지 판단한다. 검색어라면 사용자가 선택한 검색 엔진의 URL과 조합하여 새로운 URL 형태로 변환한다. URL인 경우 프로토콜과 포트와 같은 기본 요소들이 생략된 경우 이들이 기본 값인 것으로 가정한다. 만약 URL이 HSTS 목록에 있다면 https로 요청이 보내진다.
2. DNS 쿼리
URL 확인 후 UI 스레드는 I/O 스레드에게 네트워크 요청 수행을 요청한다. 이 때 도메인을 IP주소로 변환하여야 해당 웹사이트를 호스팅하고 있는 서버 컴퓨터에 요청을 보낼 수 있다. 이를 위해 도메인 이름과 IP 주소를 저장하고 있는 데이터베이스인 DNS에 요청을 보내거나 캐싱된 DNS 기록을 통해 도메인에 대응되는 IP 주소가 있는지 확인해야 한다. 직접 DNS에 요청을 보내기보단 캐싱된 DNS 기록을 통해 도메인의 IP를 확인한다.
브라우저는 크게 4개의 캐시에 DNS 기록이 있다. 먼저 브라우저 캐시를 확인한다. 브라우저는 이전에 방문한 웹사이트엥 대해 DNS 조회 결과를 캐싱한다. 다음으로 OS, 라우터, ISP 순으로 캐시를 확인한다. 이렇게 많은 곳에 캐시가 존재하는 이유는 네트워크 트래픽 및 데이터 전송 시간 개선을 위함이다.
요청 도메인이 캐시에 없다면 ISP의 DNS 서버(Public DNS)는 다른 서버로 DNS 서버로 요청(쿼리)을 보내 IP 주소를 만들어낸다. 이때 ISP의 DNS 서버처럼 직접 결과를 내려줄 수 없는 서버를 권한이 없는 서버라고 한다. 또한 도메인을 해석하는 역할을 수행하므로 Resolver, DNS Recursor라고도 한다.
도메인은 계층적 구조로 되어있다. 최상위 노드인 루트(.)부터 시작하여, 루트 도메인은 .com, .kr 등의 서브 도메인을 갖고 있는 식이다. 도메인 서버 역시 이와 마찬가지의 구조를 갖고 있다. 루트 도메인 서버는 탑 레벨 도메인 서버의 주소를 갖고 있다. 즉, 루트 도메인 서버가 탑 레벨 도메인 서버에게 요청(쿼리)할 수 있는 것이다. 이렇게 재귀적으로 각 도메인 서버에 요청(쿼리)하여 전체 도메인을 해석하고 IP 주소를 얻을 수 있다.
3. 서버와의 연결
목적지 IP 주소를 얻었다면 클라이언트와 서버의 연결을 수립해야한다. 라우터를 통해 서버까지의 경로를 알아내고, ARP를 통해 IP 주소를 물리적 네트워크 장치의 주소인 MAC 주소로 변환하여 서버와의 연결을 수립한다. HTTP는 일반적으로 TCP 연결이 이루어지며(HTTP/3.0은 UDP), 이를 위해 TCP 3-way Hand Shaking이 발생한다. HTTPS 라면 TLS 세션을 수립하기 위해 TLS Hand Shaking이 추가로 발생한다.
4. 데이터 요청
서버와의 연결 후 서버에 데이터가 도달한다. 주소창에 URL을 입력한 경우 브라우저는 GET 요청을 보낸다. 요청 종류에 따라 POST와 같은 다른 메서드를 사용할 수도 있고, 쿠키 정보 등 부가적인 정보도 함께 전달되기도 하다. https 라면 TLS 암호화와 함께 요청이 전달된다.
서버에 도달하기 전 로드 밸런서에서 악성 요청인지 확인하거나 캐시된 데이터를 응답하기도 한다. 웹 서버에 도달하였다면 해당 클라이언트에게 GET 요청이 허용되었는지 등을 분석하여 요청을 받아 처리하고 클라이언트로 응답을 전송한다.
서버의 요청에 대해 리다이렉션 응답이 올 수도 있다. 예를 들어 HTTP로 요청했는데, HTTPS로 접근해야 한다고 서버의 로드 밸런서가 리다이렉션 응답을 보낸 것이다. 이 경우 브라우저는 새로운 URL 요청을 다시 보낸다.
5. 응답 수신
브라우저의 브라우저 프로세스 내의 IO 스레드는 요청에 대한 서버의 응답을 수신한다. 이 때 안전한 응답인지 확인하는 CORB 등의 작업이 수행되기도 한다. 확인된 응답이 HTML과 같이 렌더러 프로세스가 처리할 수 있는 형태라면 UI 스레드는 렌더러 프로세스를 찾거나 생성하고, IO 스레드는 응답 데이터를 렌더러 프로세스에 전달한다. 그렇지 않으면 다운로드 매니저 등에게 데이터를 전달한다.
주소 표시줄, 보안 표시, 뒤로가기 버튼 등의 UI도 새 페이지 사이트 정보를 반영하여 갱신된다. 탭이나 창을 닫은 후 탭을 복원할 수 있도록 기록이 디스크 드라이브에 저장되기도 한다.
6. 렌더링
HTML, CSS, JS 데이터를 받은 렌더러 프로세스는 데이터를 파싱(구문 분석)하고 렌더링을 수행한다. 렌더링이 종료되면 이를 브라우저 프로세스에 알려준다(IPC 메시지 반환). 이후 새로운 리소스가 로드된다면 위의 과정과 동일하게 IO 스레드에 의해 데이터가 전달되고 이를 렌더러 프로세스가 그리게 된다.
7. 페이지 떠나기
페이지를 떠날 경우엔 어떻게 될까? 예를 들어 다시 주소창에 새로운 URL을 입력한다면 현재 사이트가 beforeunload 이벤트를 처리 후 같은 과정이 반복된다. beforeunload는 크롬 설정에 따라 실행되지 않게할 수도 있다. beforeunload 이벤트는 페이지에 입력한 데이터가 손실될 수 있음을 경고해야 하는 경우 외에는 사용하지 않는 것이 좋다. 해당 이벤트 처리도 결국 다른 사이트로의 이동에 대한 대기시간(Latency)이 늘어나는 것과 같기 때문이다.
페이지 요청이 항상 브라우저 프로세스에서 시작하는 것은 아니다. JS 코드를 통해 페이지 이동 요청이 렌더러 프로세스에서 시작하게 할 수도 있다.
같은 페이지에 다시 접속하면 어떻게 될까? 아마 해당 페이지는 캐싱되어 서버에 요청을 보내지 않고 이전에 받았던 HTML, CSS, JS, 이미지 파일 등의 리소스를 이용하여 렌더링할 것이다.
* 서비스 워커
서비스 워커란 브라우저가 백그라운드에서 실행하는 스크립트로 DOM에 접근할 수 없으며 웹 페이지의 JS와는 별개의 스레드에서 별개의 라이프 사이클을 갖고 동작한다. 서비스 워커는 HTTPS 요청에서 프록시 서버로 활용 가능하다.
서비스 워커를 데이터를 캐싱에 활용하여 인터넷 연결 없이도 정보를 보여주기도 하며, 서버의 푸시 메시지에 응답하여 서버의 새로운 컨텐츠 알림을 구현하기 위해 사용할 수도 있다. 또한 사용자가 데이터 업로드 도중 컴퓨터가 오프라인 상태가 되었을 때 서비스 워커로 데이터를 저장하고, 다시 온라인 상태가 되었을 때 업로드를 완료할 수 있다(백그라운드 동기화).
모던 웹 브라우저 들여다보기 - 네비게이션 : https://developers.google.com/web/updates/2018/09/inside-browser-part2
what happen when you type an url in browser : https://medium.com/@maneesha.wijesinghe1/what-happens-when-you-type-an-url-in-the-browser-and-press-enter-bb0aa2449c1a
what happen when-KR : https://github.com/SantonyChoi/what-happens-when-KR#g
can we use tls over tcp : https://stackoverflow.com/questions/63971335/can-we-use-tls-over-tcp-protocol