브라우저 주소창에 URL을 입력하면DNS 조회 → 연결 수립 → HTTP 요청/응답 → 브라우저 렌더링순서로 화면이 표시된다.
관련 키워드 (마인드맵 형태로 나열):
[URL 입력 후 일어나는 일]├── URL 해석│ ├── 프로토콜 / 도메인 / 경로 / 쿼리 분리│ └── URL인지 검색어인지 판단├── DNS 조회│ ├── 브라우저 캐시 → OS 캐시 → hosts 파일 → DNS Resolver│ ├── Root NS → TLD NS → Authoritative NS│ └── TTL 기반 캐싱├── 연결 수립│ ├── TCP 3-Way Handshake│ └── TLS Handshake (HTTPS)├── HTTP 요청/응답│ ├── Request Line / Headers / Body│ ├── Status Code / Headers / Body│ └── 캐싱 (Cache-Control, ETag, 304)└── 브라우저 렌더링├── HTML 파싱 → DOM 생성├── CSS 파싱 → CSSOM 생성├── Render Tree → Layout → Paint → Composite└── JavaScript 실행과 파서 블로킹
개념 설명 (내 말로):
브라우저는 주소창에 뭔가 입력되면 제일 먼저 그게 URL인지 검색어인지 판단한다. URL이라고 판단되면 프로토콜(https), 도메인(www.example.com), 경로(/path), 쿼리스트링(?q=1) 등으로 분리한다. 그런데 도메인 이름만으로는 서버에 바로 접근할 수 없다. 실제 서버의 위치는 IP 주소로 표현되는데, 우리가 입력하는 도메인은 사람이 기억하기 쉽게 만든 이름일 뿐이다. 그래서 도메인을 IP 주소로 변환해주는 과정이 필요하고, 이게 DNS(Domain Name System) 조회다.
동작 원리 / 흐름:
DNS 조회는 바로 외부 DNS 서버에 물어보는 게 아니라, 가까운 곳(캐시)부터 순서대로 확인한다.
Recursive Resolver에도 캐시가 없으면 계층적으로 올라가며 진행된다.
Recursive Resolver→ Root Name Server: "com은 어디서 관리해?" → TLD NS 주소 알려줌→ TLD Name Server: "example.com은 어디서 관리해?" → Authoritative NS 주소 알려줌→ Authoritative Name Server: "www.example.com의 IP 주소는?"→ 최종 IP 반환
조회 결과는 TTL(Time To Live) 동안 캐시에 저장된다. TTL은 이 값을 몇 초 동안 캐시해도 되는지를 나타내는 시간이다. 예를 들어 TTL이 3600이면 1시간 동안은 다시 조회하지 않고 캐시 값을 사용할 수 있다.
개념 설명 (내 말로):
IP 주소를 알아냈다고 바로 데이터를 주고받는 것은 아니다. 먼저 클라이언트와 서버가 통신 가능한 상태인지 확인하고 연결을 맺어야 한다. 인터넷에서 데이터는 패킷이라는 작은 단위로 쪼개져서 전달되는데, 이 패킷이 중간에 유실되거나 순서가 바뀌는 경우가 있다. TCP는 이런 불안정한 환경에서도 데이터의 신뢰성 있는 전송을 위한 프로토콜이다.
그래서 실제 데이터 전송 전에 연결을 맺는 과정이 필요하고, 이게 TCP의 3-Way Handshake다. 그리고 HTTPS라면 TCP 연결 뒤에 TLS Handshake도 추가로 진행된다.
동작 원리 / 흐름:
클라이언트 → 서버 : SYN (연결 시작 요청 + 시퀀스 번호 전달)서버 → 클라이언트: SYN-ACK (요청 수락 + 서버 시퀀스 번호 전달)클라이언트 → 서버 : ACK (확인 완료)→ 여기서부터 데이터 전송 가능
이 과정을 통해 양쪽 모두 연결 준비가 끝났다는 것을 확인한다.
이때 시퀀스 번호도 함께 교환하는데, 이는 데이터가 순서대로 잘 도착했는지 확인하기 위해 필요하다.
HTTPS는 TCP 연결 이후에 TLS Handshake가 이어진다.
① ClientHello: 클라이언트가 지원하는 TLS 버전, 암호화 방식 목록 전송② ServerHello + 인증서 전송: 서버가 선택한 TLS 버전, 암호화 방식 + 인증서 전송③ 브라우저가 인증서 검증: 브라우저가 CA(Certificate Authority, 공인 인증기관)를 통해 인증서 신뢰 여부 확인④ 세션 키 교환: 이후 통신에 사용할 세션 키 생성에 필요한 정보 교환
개념 설명 (내 말로):
TCP 연결이 완료되면 브라우저는 서버에 HTTP 요청을 보내고, 서버는 응답을 반환한다. 우리가 보는 HTML 문서, CSS 파일, JS 파일, 이미지 등은 결국 이 요청과 응답을 통해 전달된다. 이 단계에서 캐싱이 잘 설정돼 있으면 서버까지 가지 않고 브라우저 캐시에서 바로 응답을 꺼내올 수 있다.
동작 원리 / 흐름:
GET /index.html HTTP/1.1 ← 메서드 + 경로 + 프로토콜 버전Host: www.example.com ← 요청 대상 도메인User-Agent: Mozilla/5.0 ... ← 브라우저 정보Accept: text/html ← 받을 수 있는 콘텐츠 타입Cookie: session=abc123 ← 저장된 쿠키
HTTP/1.1 200 OK ← 상태 코드Content-Type: text/html; charset=UTF-8 ← 응답 본문의 타입Cache-Control: max-age=3600 ← 3600초(1시간) 동안 캐시 유효ETag: "abc123" ← 리소스 식별자 (변경 감지용)<!DOCTYPE html> ← 실제 본문<html>...
개념 설명 (내 말로):
서버가 HTML을 응답하면 브라우저는 이를 그대로 보여주는 것이 아니라, 파싱해서 화면을 그릴 수 있는 구조로 바꾼 뒤 렌더링한다.
이 과정은 HTML을 받는 순간부터 순서대로 진행되며, DOM과 CSSOM이 준비되면 Render Tree를 만들고, 이후 Layout, Paint, Composite 단계를 거쳐 최종 화면을 출력한다.
동작 원리 / 흐름:
HTML 수신 시작
브라우저는 HTML을 위에서 아래로 읽으면서 문서 구조를 해석하고 DOM을 만든다. DOM은 문서를 트리 형태로 표현한 객체 구조다.
CSS도 별도로 파싱해서 CSSOM을 만든다.
브라우저는 DOM만이 아니라 각 요소에 어떤 스타일이 적용되는지도 알아야 화면을 그릴 수 있다.
DOM과 CSSOM을 합쳐 실제 화면에 필요한 노드만 모은 Render Tree를 만든다. 이때 display: none요소는 제외되고, visibility: hidden요소는 포함된다.
각 요소의 위치와 크기를 계산하는 단계다. 브라우저가 각 박스를 화면 어디에 어떤 크기로 배치할지 정한다고 보면 된다.
기본 <script> 태그는 HTML 파싱 중간에 등장하면 파싱을 멈추게 한다. 브라우저는 스크립트를 다운로드하고 실행한 뒤 다시 HTML 파싱을 이어간다.
<!-- 기본 script: HTML 파싱 중단 → JS 다운로드 + 실행 후 재개 --><scriptsrc="app.js"></script><!-- defer: 다운로드는 병렬, 실행은 HTML 파싱 완료 후 --><scriptsrc="app.js"
| 구분 | HTTP/1.1 | HTTP/2 | HTTP/3 |
| 전송 계층 | TCP | TCP | QUIC(UDP 기반) |
| 멀티플렉싱 | ❌ 요청 순서대로 처리 | ✅ 하나의 연결로 병렬 처리 | ✅ |
| HOL Blocking* | TCP + HTTP 레벨 발생 | TCP 레벨만 남음 | 해결 |
| 헤더 압축 | ❌ | ✅ HPACK | ✅ QPACK |
| 초기 연결 비용 | TCP + TLS | TCP + TLS (연결 수는 적음) |
*Head-of-Line Blocking: 앞 요청이 처리되기 전까지 뒤 요청이 대기해야 하는 현상
외부 리소스를 곧 사용할 것이 확실하면, DNS 조회나 연결 자체를 미리 시작할 수 있다.
<link rel="dns-prefetch" href="//fonts.googleapis.com"><link rel="preconnect" href="<https://cdn.example.com>"
[도입 - 핵심 정의 먼저]“브라우저에 URL을 입력하면,서버를 찾고 요청을 보낸 뒤 받은 응답을 화면에 렌더링하는 과정이 순서대로 일어납니다.전체 흐름은 DNS 조회, TCP/TLS 연결, HTTP 요청·응답, 그리고 브라우저 렌더링 단계로 나눌 수 있습니다.”[부연 - 왜/어떻게]“먼저 DNS 조회를 통해 도메인을 실제 서버의 IP 주소로 변환합니다.이때 브라우저나 OS 캐시를 먼저 확인하고, 없으면 DNS 서버를 따라가며 IP를 찾습니다.IP를 알게 되면 서버와 TCP 연결을 맺고, HTTPS라면 TLS Handshake를 추가로 거쳐 암호화 통신을 준비합니다.이후 브라우저가 HTTP 요청을 보내고 서버가 HTML 같은 리소스를 응답합니다.캐시가 유효하면 서버까지 가지 않고 브라우저 캐시를 사용하고,만료된 경우에도 ETag를 기반으로 재검증해서 304 응답으로 데이터를 줄일 수 있습니다.마지막으로 브라우저는 HTML과 CSS를 파싱해 DOM과 CSSOM을 만들고,이를 기반으로 Render Tree를 구성한 뒤Layout, Paint, Composite 단계를 거쳐 화면을 그립니다.이때 script 태그는 파싱을 막을 수 있어서 로딩 방식이 렌더링 성능에 영향을 줍니다.”[마무리 - 실무 연결]“그래서 이 흐름을 알고 있으면 네트워크 문제인지, 캐시 문제인지, 렌더링 문제인지 구분해서 성능 최적화 포인트를 더 잘 찾을 수 있습니다.”
면접관이 바쁠 때, 딱 1분 안에 설명하는 버전
브라우저에 URL을 입력하면먼저 DNS 조회를 통해 도메인을 IP 주소로 변환하고,그다음 TCP 연결을 맺습니다.HTTPS라면 TLS Handshake까지 진행됩니다.이후 HTTP 요청과 응답이 오가고,캐시가 유효하면 서버까지 가지 않고 브라우저 캐시를 사용할 수 있습니다.마지막으로 브라우저는 HTML과 CSS를 파싱해 DOM과 CSSOM을 만들고,Render Tree를 구성한 뒤 Layout, Paint, Composite 단계를 거쳐화면을 렌더링합니다.이 전체 흐름을 기준으로 각 단계에서 성능 최적화를 적용할 수 있습니다.
A: HTTP는 요청과 응답이 평문으로 전달되기 때문에, 중간에서 내용을 읽거나 변조할 수 있습니다. 반면 HTTPS는 TLS를 통해 통신 내용을 암호화해서 이런 위험을 줄여줍니다. 또 서버 인증서를 기반으로 내가 접속한 서버가 신뢰할 수 있는 서버인지도 확인할 수 있습니다. 요즘은 브라우저가 HTTP 사이트를 안전하지 않다고 표시하고, SEO 측면에서도 HTTPS가 더 유리해서 사실상 기본이라고 생각합니다.
A: 첫 방문 때 받아둔 정보들을 다시 활용할 수 있기 때문입니다. 예를 들어 DNS 캐시가 남아 있으면 IP를 다시 찾는 과정을 줄일 수 있고, 정적 리소스가 브라우저 캐시에 있으면 네트워크 요청 없이 바로 사용할 수도 있습니다. 캐시가 만료됐더라도 ETag를 통해 서버에 변경 여부만 확인해서, 바뀌지 않았다면 304 응답으로 기존 캐시를 계속 사용할 수 있습니다. 그래서 두 번째 방문이 더 빠르게 느껴집니다.
A: 저는 먼저 DevTools의 Network 탭에서 병목이 네트워크인지, 리소스 다운로드인지, 렌더링인지 나눠서 보려고 합니다. 우선 TTFB가 긴지 보고, 길다면 DNS 조회나 TCP/TLS 연결, 서버 처리 시간 중 어디가 느린지 Timing으로 확인합니다. 반대로 TTFB는 괜찮은데 화면이 늦게 뜨면 번들 크기, 이미지 최적화, 불필요한 요청 수를 보고, 렌더링이 느리면 Performance 탭에서 Long Task나 레이아웃 재계산이 많은지 확인합니다.
A: JS, CSS, 이미지처럼 자주 바뀌지 않는 정적 파일은 길게 캐싱하고, 파일명에 해시를 붙이는 방식이 일반적이라고 생각합니다. 예를 들어 app.a1b2c3.js처럼 배포하면 내용이 바뀔 때마다 URL도 함께 바뀌기 때문에, 브라우저는 새 파일을 자연스럽게 다시 받게 됩니다. 반면 HTML은 보통 no-cache로 두어서, 매 요청마다 최신 파일 경로를 참조할 수 있게 하는 방식이 많이 쓰입니다.
A: 아닙니다. no-cache는 캐시에 저장하지 말라는 뜻이 아니라, 캐시에 저장은 하되 사용할 때마다 서버에 다시 확인하라는 의미입니다. 그래서 브라우저는 ETag 같은 값을 이용해서 조건부 요청을 보내고, 서버가 변경 없음을 확인해주면 304 응답을 받아 기존 캐시를 계속 사용합니다. 반대로 아예 저장 자체를 하지 않는 건 no-store입니다.
A: 외부 스크립트에 defer를 사용할 수 있다면 꼭 body 끝에 둘 필요는 없다고 생각합니다. 기본 script는 HTML 파싱을 막지만, defer는 다운로드를 파싱과 병렬로 진행하고 실행은 HTML 파싱이 끝난 뒤에 하기 때문입니다. 또 여러 스크립트의 실행 순서도 보장됩니다. 반면 async는 다운로드가 끝나는 즉시 실행되기 때문에 순서 보장이 필요 없는 독립적인 스크립트에 더 적합합니다.
여기서 중요한 점은, HTTPS는 단순히 암호화만 하는 것이 아니라 서버가 신뢰할 수 있는 대상인지 인증서 기반으로 검증도 한다는 것이다.
RTT(Round Trip Time)는 요청을 보내고 응답을 받을 때까지의 왕복 시간이다. TCP Handshake, TLS Handshake는 각각 RTT 비용이 들어간다. 그래서 서버 위치가 멀수록 첫 연결이 느리게 느껴질 수 있다.
예를 들어 서울↔서울이면 RTT가 1ms 내외지만, 서울↔미국 서버라면 150ms 이상이 될 수 있어서 이 차이가 페이지 로딩 체감에 직접 영향을 준다.
브라우저는 응답 헤더를 보고 캐시를 사용할지 판단한다. 이때 Cache-Control은 캐시의 유효 시간을 정하고, ETag는 캐시가 만료됐을 때 서버에 변경 여부를 확인하는 기준이 된다.
요청 발생→ 브라우저 캐시에 유효한 응답이 있나? (max-age 기준)→ 있으면: 서버에 다시 요청하지 않고 캐시에서 바로 사용→ 없거나 만료되면: If-None-Match 헤더에 이전 ETag를 담아 재검증 요청→ 서버의 ETag와 같으면: 304 Not Modified→ 다르면: 200 OK + 새로운 본문
여기서 ETag는 리소스 버전 식별자 역할을 한다. 브라우저는 이전에 저장한 ETag를 If-None-Match 헤더에 담아 보내고, 서버는 같으면 304를 응답한다.
304는 본문 없이 헤더만 보내기 때문에 네트워크 비용을 줄일 수 있다.
계산이 끝난 요소를 실제 픽셀로 그리는 단계다. 이 과정에서 색상, 글자, 이미지, 테두리 같은 시각 정보가 화면에 반영된다.
여러 레이어를 합성해서 최종 화면을 만든다. transform, opacity는 이 단계에서 처리될 수 있어서 비교적 성능 부담이 적다.
| 첫 연결 1-RTT, 재연결 0-RTT 가능 |
정적 파일은 오래 캐싱하되, 파일명에 해시를 넣어 버전을 관리하는 방식이 자주 쓰인다. (ex. app.a1b2c3.js )
파일 내용이 바뀌면 이름 자체가 달라지므로, 오래 캐싱해도 최신 파일을 안전하게 내려줄 수 있다.