How Browsers Work · Part 2 — From URL to Pixels
A bird's-eye walkthrough of everything that happens between pressing Enter and the first paint: URL parsing, DNS, TCP/TLS, the HTTP request, response handling, and handing bytes to the renderer.
Phần 1 đã cho bạn bản đồ: trình duyệt là nhiều tiến trình, và renderer biến code thành pixel. Phần này theo một lần điều hướng từ đầu đến cuối — điều gì diễn ra giữa lúc nhấn Enter ở address bar và lần vẽ pixel đầu tiên.
Ta giữ góc nhìn tổng thể ở đây; các phần sau sẽ zoom vào phân tích HTML (Phần 3), CSS (Phần 4), và layout/paint (Phần 5). Chủ đề xuyên suốt: tiến trình browser sở hữu điều hướng; nó chọn renderer và bàn giao response ở bước commit, rồi renderer tiếp tục loading.
1. Điều hướng bắt đầu ở tiến trình browser
Khi bạn nhấn Enter, luồng UI trong tiến trình browser nhận input — không phải renderer. Việc đầu tiên là biến chuỗi đó thành thứ có thể hành động:
- Phân tích và chuẩn hóa URL — thêm scheme nếu thiếu (
example.com→https://example.com), viết thường host, percent-encode ký tự không hợp lệ, resolve đường dẫn tương đối nếu bạn đang sửa URL hiện có. - Tìm kiếm vs URL — omnibox dùng heuristic và cấu hình công cụ tìm kiếm để phân biệt URL với query; đây không phải quy tắc đơn giản kiểu “có dấu chấm thì là URL”.
- Kiểm tra HSTS — nếu host nằm trong danh sách preload HTTP Strict Transport Security, yêu cầu
http://được nâng lênhttps://trước mọi I/O mạng. - Chọn đường xử lý theo scheme và policy —
http:/https:đi qua network stack;data:,file:, URL nội bộ hay scheme tùy chỉnh có pipeline và giới hạn riêng. Safe Browsing và policy doanh nghiệp có thể chặn navigation.
Nếu đây là cross-document navigation rời một trang đang mở, Chromium chạy beforeunload của document cũ trước network request; user có thể hủy điều hướng. Sau đó, URL cần mạng mới đi vào network stack. Trình tự chi tiết nằm trong Life of a Navigation của Chromium.
Điều hướng là theo URL, theo tab — mỗi lần nhấn Enter (hoặc click link, hay
location.href = …) chạy pipeline này độc lập, dù tái sử dụng kết nối có thể bỏ qua vài bước khi quay lại.
2. DNS: biến hostname thành địa chỉ IP
Trình duyệt biết muốn đi đâu (example.com) nhưng mạng cần địa chỉ IP. Phân giải DNS lấp khoảng trống đó.
Phân giải thường đi qua cache và resolver, nhưng đường chính xác phụ thuộc cấu hình trình duyệt/HĐH:
Chromium host cache
↓ miss
Built-in resolver / OS resolver / DNS-over-HTTPS (tùy cấu hình)
↓
Recursive resolver → authoritative nameservers
↓
IP address(es) returned
Network service (không phải renderer) điều phối tra cứu này — nhớ từ Phần 1 renderer không mở socket trực tiếp. Cache hit tránh một round-trip DNS; cache miss phải chờ resolver và có thể thử nhiều địa chỉ IPv6/IPv4.
Trình duyệt hiện đại cũng hỗ trợ DNS-over-HTTPS (DoH) khi cấu hình. TTL, negative caching và cách cache browser tương tác với cache HĐH là chi tiết implementation; đóng một tab không đồng nghĩa xóa DNS cache dùng chung của browser.
3. TCP và TLS: mở kênh bảo mật
Có IP rồi, HTTP/1.1 và HTTP/2 thường mở kết nối TCP tới cổng 443 (HTTPS) hay 80 (HTTP). Đây là bắt tay ba bước bạn học ở lớp mạng:
Client ── SYN ──────────────► Server
Client ◄── SYN-ACK ────────── Server
Client ── ACK ──────────────► Server
(connection established)
Với HTTPS trên TCP, bắt tay TLS chạy trước khi HTTP chảy. Ở mức cao:
- Client gửi phiên bản TLS và bộ mật mã hỗ trợ.
- Server chọn mật mã, gửi chuỗi chứng chỉ.
- Client xác minh chứng chỉ (chuỗi tin cậy, khớp hostname, thu hồi nếu kiểm tra).
- Hai bên dẫn xuất khóa phiên và chuyển sang giao tiếp mã hóa.
Một kết nối HTTPS lạnh qua TCP thường trả 1 RTT cho TCP rồi 1 RTT cho full handshake TLS 1.3; resumption có thể giảm thêm. HTTP/3 là nhánh khác: nó chạy trên QUIC/UDP và tích hợp TLS 1.3, không có TCP handshake riêng. Nếu browser đã có kết nối HTTP/2 hoặc HTTP/3 đủ điều kiện, nó tái dùng kết nối; HTTP/2/3 còn có thể coalesce một kết nối cho nhiều origin khi chứng chỉ, DNS và policy cho phép.
Thẻ gợi ý
preconnectvàdns-prefetchcho phép trang làm ấm kết nối trước điều hướng —<link rel="preconnect" href="https://cdn.example.com">phân giải DNS và mở TCP+TLS sớm. Phần 9 đi sâu hơn về cache và HTTP.
4. Yêu cầu và phản hồi HTTP
Khi kênh mở, trình duyệt gửi yêu cầu HTTP:
:method: GET
:scheme: https
:authority: example.com
:path: /articles/browser-internals
Accept: text/html,application/xhtml+xml,…
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br
Cookie: session_id=abc123; theme=dark
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
User-Agent: Mozilla/5.0 …
Các phần chính:
- Method —
GETcho điều hướng;POSTcho submit form. - Headers —
Acceptbáo server trình duyệt xử lý được gì;Cookiegắn cookie đã lưu cho origin này; headerSec-Fetch-*mô tả ngữ cảnh bảo mật của yêu cầu. - Credentials — cookie được chọn theo host/domain, path,
Secure,SameSite, partition và policy người dùng. TLS client certificate, nếu có, được thương lượng ở tầng TLS chứ không phải một header cookie.
Server phản hồi bằng status, header, và body:
:status: 200
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Cache-Control: max-age=3600
Set-Cookie: session_id=xyz789; HttpOnly; Secure; SameSite=Lax
<!DOCTYPE html>…
Network service và tiến trình browser xử lý header phản hồi, rồi đưa ra vài quyết định trước khi bàn giao response cho renderer:
| Status / signal | Hành động trình duyệt |
|---|---|
| 301/302/307/308 | Theo redirect (có thể nhiều bước); mỗi bước lặp DNS/TCP/TLS nếu khác origin |
| 401 | Có thể kích hoạt HTTP-auth prompt khi có WWW-Authenticate; nếu không, render body lỗi như response bình thường |
| 403 | Thường vẫn commit và render body phản hồi với status lỗi |
Content-Disposition: attachment | Coi là tải xuống, không phải điều hướng |
Content-Type: application/pdf | Có thể dùng viewer tích hợp hay tải xuống |
| 204/205 | Không tạo document mới; document hiện tại vẫn active |
Thiếu Content-Type | Có thể sniff một phần body nếu policy cho phép; X-Content-Type-Options: nosniff tắt một số đường sniff |
5. Có thật sự tạo document mới không?
Không phải mọi navigation hay phản hồi HTTP đều tạo document mới trong tab:
- Same-document navigation — đổi fragment hay
history.pushState()giữ nguyênDocument, không đi qua pipeline này như một page load mới. 204/205— response thành công nhưng không có document thay thế; trang cũ vẫn active.- Tải xuống —
Content-Disposition: attachmentkhiến browser chuyển sang download và không commit document mới. - Navigation trong frame bị chặn —
frame-ancestors/X-Frame-Optionscó thể từ chối nhúng response. COOP không tự mở URL sang tab khác; nó có thể tách document mới sang browsing-context group khác khi commit.
Nếu không rơi vào các nhánh trên, browser chọn renderer và chuẩn bị commit điều hướng. Document cũ có thể bị hủy, hoặc được giữ sống trong bfcache để dùng khi Back/Forward.
6. Chọn renderer và commit điều hướng
Đây là lúc kiến trúc Phần 1 trở nên cụ thể. Tiến trình browser phải quyết định renderer nào nhận HTML đến:
Browser process
│
├─ Same site as current tab? → reuse existing renderer (maybe)
├─ Cross-site navigation? → pick or spawn a new renderer (Site Isolation)
├─ Back/forward? → may swap to a frozen cached renderer
└─ Commit navigation → IPC: "Navigate" + response body stream
│
▼
Renderer process (sandboxed)
└─ Begin receiving bytes, start HTML parsing…
Với full Site Isolation trên desktop, điều hướng từ bank.com sang evil.com dùng renderer khác. Điều hướng cùng site thường có thể tái sử dụng process, nhưng quyết định còn phụ thuộc SiteInstance, COOP, process limit và trạng thái hiện tại — đừng coi “một tab = một process” là invariant.
Commit là cột mốc IPC: address bar cập nhật, lịch sử phiên thêm mục mới, renderer bắt đầu tiêu thụ stream body phản hồi. Trước commit, người dùng vẫn thấy trang cũ (dù spinner tab có thể đã quay).
Back-forward cache (bfcache) giữ sống Document cùng state liên quan và tạm dừng tác vụ của trang để Back/Forward gần như tức thì — không phải lúc nào cũng đóng băng cả renderer process. Eligibility thay đổi theo browser và phiên bản: Chrome hiện có thể cache một số trang
Cache-Control: no-storean toàn, nên hãy kiểm tra Application → Back-forward Cache hoặcnotRestoredReasonsthay vì thuộc một blacklist cũ. Xem thay đổino-storecủa Chrome.
7. Renderer nhận byte — bước đầu tới pixel
Sau commit, tiến trình renderer sở hữu phần còn lại của hành trình tới pixel. Body phản hồi đến dưới dạng stream byte — renderer không chờ cả tài liệu mới bắt đầu.
Response bytes (streaming)
│
▼
┌──────────────────┐
│ HTML parser │ → builds DOM incrementally (Part 3)
└────────┬─────────┘
│ discovers <link rel="stylesheet">, <script>, <img>…
▼
┌──────────────────┐ ┌──────────────────┐
│ Preload scanner │ ──► │ Network fetches │ (CSS, JS, images in parallel)
└──────────────────┘ └──────────────────┘
│
▼
┌──────────────────┐
│ CSS parser │ → builds CSSOM (Part 4)
└────────┬─────────┘
▼
┌──────────────────┐
│ Style + Layout │ → render tree, geometry (Part 5)
│ + Paint │
│ + Composite │ → GPU process draws layers
└────────┬─────────┘
▼
First paint (FP) / First Contentful Paint (FCP)
Lần paint đầu có thể xảy ra khi browser có đủ DOM tăng dần và các stylesheet đang chặn để vẽ cái gì đó — không cần đợi toàn bộ document hay mọi tài nguyên. Đó là lý do CSS render-blocking trì hoãn paint, còn nhiều ảnh ngoài viewport thì không.
Yêu cầu tài nguyên con (<script src="…">, @import, fetch() từ JS) quay lại network service — cùng pool kết nối, cùng cookie jar, cùng thực thi CORS. Renderer yêu cầu; tiến trình browser (qua network service) fetch và stream byte trả về qua IPC.
8. Dòng thời gian điều hướng đầy đủ (một sơ đồ)
Gom lại — một điều hướng HTTPS lạnh:
Enter URL
│
├─ [Browser] Parse URL, HSTS, security checks
│
├─ [Browser] beforeunload (nếu cần; có thể hủy navigation)
│
├─ [Network] DNS lookup (nếu cache miss)
│
├─ [Network] TCP + TLS 1.3, hoặc QUIC + TLS cho HTTP/3
│
├─ [Network] HTTP request → HTTP response (headers + body stream)
│ │
│ ├─ Redirect? → request URL kế tiếp, có thể reuse connection
│ ├─ 204/205? → giữ document cũ, STOP
│ └─ Download? → lưu file, STOP
│
├─ [Browser] Pick/spawn renderer (Site Isolation + response policy)
│
├─ [Browser → Renderer] Commit navigation, stream body
│
└─ [Renderer] Parse HTML → DOM → CSSOM → layout → paint → composite
│
└──► First paint visible on screen
Chi phí thực tế phụ thuộc RTT, server think time, protocol, cache và khả năng reuse connection; không có bước nào luôn chiếm ưu thế. Panel Network của DevTools cho thấy timing request; panel Performance cho thấy parse và render phía renderer.
Tóm tắt
- Điều hướng thuộc tiến trình browser: phân tích URL, HSTS, search-vs-URL, và kiểm tra bảo mật diễn ra trước mọi I/O mạng.
- Với HTTP/1.1/2, đường lạnh thường là DNS → TCP → TLS → HTTP; HTTP/3 dùng QUIC + TLS. Cache và connection reuse có thể bỏ qua nhiều bước.
- Trình duyệt xử lý redirect, sniff MIME, tải xuống vs tài liệu, và
beforeunloadtrước khi commit. - Site Isolation quyết định renderer nào nhận trang; commit là điểm bàn giao.
- Renderer stream byte vào pipeline DOM → CSSOM → layout → paint → composite; lần paint đầu đến trước khi trang tải xong.
Phần tiếp theo: Phân tích HTML & DOM — byte thành cây sống thế nào, vì sao script chặn parse, và preload scanner làm gì.