// API: https://api.staging.example.com (Express)
app.use(cors({ origin: '*', credentials: true }));
res.cookie('sid', token, { httpOnly: true });
// SPA: https://app.staging.example.io
await fetch('https://api.staging.example.com/me');
Networking Fundamentals
draftedTCP/IP, DNS, HTTP/1.1/2/3, TLS, CDN, load balancer, proxy, VPN, WebSocket/SSE, CORS — nhìn từ góc backend production.
0/45 rated · mastery 0%
Bài học
10 bài · ~147 phút đọc. Học theo thứ tự, rồi làm câu hỏi.- 01~18 phút· 4 câuverify
Hành trình của một HTTPS request: tầng mạng, RTT, TCP vs UDP
Mô hình tầng (IP, TCP/UDP, TLS, HTTP), đếm round-trip từ lúc gõ URL tới byte đầu tiên, vì sao latency do RTT quyết định chứ không phải băng thông, và cách điều tra 'API chậm' từ phía client.
- 02~14 phút· 5 câuverify
TCP connection lifecycle: keep-alive, TIME_WAIT, slow start và ECONNRESET
Vòng đời một TCP connection, vì sao tái sử dụng connection là tối ưu số một, TIME_WAIT và cạn ephemeral port, congestion control/slow start, và các lỗi idle connection bị middlebox cắt.
- 03~15 phút· 5 câuverify
DNS cho backend: record, TTL, cache nhiều tầng và DNS trong Node.js
Phân giải tên từ resolver tới authoritative, A/AAAA/CNAME/ALIAS và vì sao không CNAME ở apex, TTL và cache nhiều tầng, dns.lookup vs dns.resolve trong Node, IPv6 localhost, và cách migrate bằng DNS mà không bỏ rơi traffic.
- 04~16 phút· 5 câuverify
TLS & HTTPS: handshake 1.3, certificate chain, SNI/ALPN, 0-RTT và nơi terminate TLS
TLS thực sự bảo vệ gì, key exchange (EC)DHE và forward secrecy, certificate public key dùng để ký chứ không phải mã hoá dữ liệu, xác thực chain và các lỗi Node thường gặp, SNI/ALPN, rủi ro replay của 0-RTT, và terminate TLS ở đâu.
- 05~14 phút· 4 câuverify
HTTP: ngữ nghĩa method, idempotency và HTTP/1.1 → HTTP/2 → HTTP/3
Safe vs idempotent và vì sao nó quyết định retry, idempotency key, head-of-line blocking ở từng phiên bản HTTP, multiplexing của HTTP/2 và rủi ro ở scale (Rapid Reset, LB lệch tải), QUIC/HTTP/3 và cách rollout.
- 06~13 phút· 5 câuverify
Same-Origin Policy & CORS: origin, preflight, credentials và vì sao CORS không chống CSRF
Origin và site khác nhau thế nào, SOP chặn đọc chứ không chặn gửi, simple request vs preflight, cookie cross-origin với credentials và SameSite, lỗi echo Origin bằng regex, và cách chống CSRF đúng.
- 07~15 phút· 6 câuverify
Proxy, load balancer và VPN: L4 vs L7, thuật toán cân bằng, X-Forwarded-For, health check
Forward vs reverse proxy, VPN và zero-trust khác proxy ở đâu, L4 vs L7 load balancer và nơi TLS terminate, round-robin/least-connections/consistent hashing, lấy IP client đúng qua X-Forwarded-For, và thiết kế health check không gây cascading failure.
- 08~13 phút· 4 câuverify
CDN & HTTP caching: Cache-Control, Vary, cache key và edge cho multi-tenant
Freshness vs validation, các directive Cache-Control cho CDN trước API, ETag/304, Vary và cache key, stale-while-revalidate, lỗi rò dữ liệu giữa tenant qua cache, và thiết kế edge cho custom domain + HTTPS.
- 09~15 phút· 4 câuverify
Timeout chain & 5xx sau proxy: 502/503/504, keep-alive race, Nginx upload và retry policy
Đọc 502/503/504/499 để biết điều tra ở đâu, vì sao Node sau ALB trả 502 lẻ tẻ, các timeout của Node và Nginx, upload lớn qua proxy, và thiết kế timeout/retry nhất quán từ client tới DB bằng deadline propagation.
- 10~14 phút· 5 câuverify
Realtime: polling, SSE, WebSocket, Socket.IO và scale kết nối lâu dài
Chọn giữa short/long polling, Server-Sent Events và WebSocket, handshake WebSocket và những gì proxy cần, vì sao SSE bị dồn cục sau proxy, sticky session và pub/sub khi scale Socket.IO, và thiết kế fan-out cho hàng trăm nghìn kết nối.
Tóm tắt & cheat sheet của track
TL;DR
- Mỗi HTTP request đi qua chuỗi DNS → TCP (hoặc QUIC) → TLS → HTTP; latency thật nằm ở số round-trip (RTT), không phải băng thông.
- Senior interview hỏi networking qua triệu chứng production: 502 lẻ tẻ sau load balancer,
ECONNRESET, DNS đổi mà client vẫn gọi IP cũ, CORS preflight làm chậm, WebSocket rớt khi scale. - Nắm 5 trục: connection lifecycle & keep-alive, HTTP versions & head-of-line blocking, TLS handshake & certificate, DNS caching/TTL, proxy/LB/CDN (header nào bị đổi, timeout nào đứng trước timeout nào).
- CORS là cơ chế browser nới lỏng Same-Origin Policy để JS được đọc response cross-origin — nó không phải cơ chế chống CSRF.
Khái niệm cốt lõi
| Khái niệm | Một câu | Ví dụ ngắn |
|---|---|---|
| TCP | Stream tin cậy, có thứ tự, có congestion control; mở bằng 3-way handshake | SYN → SYN-ACK → ACK = 1 RTT trước khi gửi byte đầu tiên |
| UDP | Datagram không kết nối, không đảm bảo thứ tự/đến nơi | DNS query, QUIC, video call |
| DNS | Hệ thống phân giải tên → record (A, AAAA, CNAME, MX, TXT...) có TTL | api.example.com A 203.0.113.10 TTL 60 |
| TLS | Mã hoá + xác thực server (certificate) + toàn vẹn dữ liệu trên TCP | TLS 1.3 handshake = 1 RTT |
| HTTP/1.1 | Text protocol, 1 request "đang bay" mỗi connection | Browser mở ~6 connection/origin để song song |
| HTTP/2 | Binary framing, multiplex nhiều stream trên 1 TCP connection, HPACK | 100 request nhỏ chung 1 connection |
| HTTP/3 | HTTP trên QUIC (UDP); loại bỏ TCP head-of-line blocking, 0-RTT/1-RTT | Mạng di động đổi IP vẫn giữ connection (connection ID) |
| Reverse proxy / LB | Đứng trước server, terminate TLS, phân phối tải, thêm X-Forwarded-* | Nginx, ALB, Envoy |
| CDN | Cache ở edge gần user theo Cache-Control/Vary | Cache-Control: public, s-maxage=300 |
| CORS | Server khai báo origin nào được đọc response qua header Access-Control-* | Preflight OPTIONS cho Content-Type: application/json |
| WebSocket | Kênh full-duplex nâng cấp từ HTTP (101 Switching Protocols) | Chat, realtime dashboard |
| SSE | Stream một chiều server → client qua HTTP thường (text/event-stream) | Notification, progress bar |
Cơ chế hoạt động
Từ URL tới response
TLS 1.3 handshake (rút gọn)
- Key exchange dùng (EC)DHE → forward secrecy; public key trong certificate dùng để ký (CertificateVerify), không phải để "mã hoá dữ liệu". RSA key exchange đã bị loại khỏi TLS 1.3.
- Dữ liệu thật được mã hoá bằng symmetric key (AES-GCM / ChaCha20-Poly1305) suy ra từ shared secret.
Timeout chain qua proxy
Quy tắc vàng: upstream (app) phải giữ connection idle lâu hơn downstream (LB); nếu app đóng trước, LB có thể gửi request vào socket vừa bị đóng → 502 lẻ tẻ.
Trade-offs
| Lựa chọn | Ưu | Nhược | Khi nào dùng |
|---|---|---|---|
| HTTP/1.1 | Đơn giản, debug dễ, mọi proxy hỗ trợ | HOL blocking theo connection, nhiều connection | Service nội bộ đơn giản |
| HTTP/2 | Multiplex, header compression, 1 connection | TCP HOL khi mất gói; một connection = một điểm nghẽn/LB kém đều | Browser ↔ edge, gRPC |
| HTTP/3 (QUIC) | Không TCP HOL, handshake nhanh, connection migration | UDP có thể bị firewall chặn, CPU cao hơn, tooling kém hơn | Mobile, mạng loss cao, edge/CDN |
| L4 LB | Nhanh, không hiểu HTTP, pass-through TLS | Không route theo path/header | TCP/gRPC throughput cao |
| L7 LB | Route theo host/path, retry, header, TLS termination | Tốn CPU, thêm hop, phải cấu hình timeout | API gateway, web app |
| Polling | Dễ, cache được, stateless | Trễ + lãng phí request | Cập nhật hiếm |
| SSE | HTTP thường, auto-reconnect, qua proxy dễ | Một chiều, text only | Notification, stream log |
| WebSocket | Hai chiều, latency thấp | Stateful, sticky/pub-sub khi scale, proxy phải hỗ trợ Upgrade | Chat, collaboration, game |
Pitfalls
- Nghĩ CORS chặn request: browser vẫn gửi simple request (kể cả cookie nếu
SameSitecho phép); CORS chỉ quyết định JS có đọc được response không. Access-Control-Allow-Origin: *cùngcredentials: 'include'→ browser từ chối. Echo origin động thì phải whitelist và thêmVary: Origin.- Node
keepAliveTimeout(mặc định 5s) nhỏ hơn idle timeout của LB (ALB mặc định 60s) → 502 ngẫu nhiên. - Hạ TTL DNS ngay lúc migrate là muộn — phải hạ trước ít nhất một chu kỳ TTL cũ.
- Tin
X-Forwarded-Fortừ client mà không cấu hìnhtrust proxyđúng số hop → IP spoofing, rate limit sai. - Retry tự động request không idempotent (POST) khi timeout → tạo đơn trùng.
- HTTP/2 Server Push đã bị các browser lớn bỏ — đừng thiết kế dựa vào nó; dùng
103 Early Hints/ preload.
Cheat sheet
- RTT cold HTTPS (TCP + TLS 1.3): ~2 RTT trước byte response đầu; TLS 1.2 full handshake: ~3 RTT; HTTP/3: ~1 RTT (0-RTT khi resume, có rủi ro replay).
502= proxy nhận response lỗi/connection bị đóng từ upstream ·504= upstream không trả lời kịp ·499(nginx) = client tự đóng.- Idempotent:
GET, HEAD, PUT, DELETE, OPTIONS; không idempotent:POST,PATCH(thường). - Simple CORS request: method
GET/HEAD/POST+ chỉ CORS-safelisted headers +Content-Type∈text/plain,multipart/form-data,application/x-www-form-urlencoded. TIME_WAITnằm ở phía chủ động đóng connection; nhiều connection ngắn → cạn ephemeral port.- DNS: CNAME không đặt được ở zone apex → dùng ALIAS/ANAME/CNAME flattening của provider.
- WebSocket:
Upgrade: websocket+101; proxy phải forwardUpgrade/Connectionheaders và có idle timeout đủ dài / ping.
References
- MDN — An overview of HTTP ↗
- MDN — Cross-Origin Resource Sharing (CORS) ↗
- RFC 9110 — HTTP Semantics ↗
- RFC 9113 — HTTP/2 ↗
- RFC 9114 — HTTP/3 ↗
- RFC 9000 — QUIC ↗
- RFC 8446 — TLS 1.3 ↗
- RFC 9293 — TCP ↗
- RFC 6455 — The WebSocket Protocol ↗
- Fetch Standard — CORS protocol ↗
- Node.js — http module ↗
- Node.js — dns module ↗
- AWS — Application Load Balancer idle timeout ↗
Personal notes (Notion)
Ghi chú cá nhân — có thể sai hoặc lỗi thời, dùng để tham khảo.
Interview Questions
Showing 45 / 45
<!-- attacker.com -->
<form action="https://shop.example.com/api/address/delete" method="POST">
<input name="id" value="123" />
</form>
<script>document.forms[0].submit()</script>
// ALB → Nginx → Node: two proxies we control
app.set('trust proxy', 2);
app.get('/whoami', (req, res) => res.json({ ip: req.ip, ips: req.ips }));
server.listen(3000, '127.0.0.1'); // IPv4 only
await fetch('http://localhost:3000/health'); // may try ::1 first
const server = app.listen(3000);
server.keepAliveTimeout = 65_000; // > ALB idle timeout (60s)
server.headersTimeout = 66_000; // must exceed keepAliveTimeout
server {
listen 443 ssl;
client_max_body_size 0; # "fix": unlimited
proxy_read_timeout 3600s;
proxy_request_buffering on;
location /upload {
proxy_pass http://node_upstream;
}
}
import https from 'node:https';
export function callPricing(sku: string) {
return new Promise((resolve, reject) => {
const req = https.request(
{ host: 'pricing.internal', path: `/p/${sku}`, agent: new https.Agent({ keepAlive: true }) },
(res) => { let b = ''; res.on('data', (c) => (b += c)); res.on('end', () => resolve(JSON.parse(b))); },
);
req.on('error', reject);
req.end();
});
}
app.use((req, res, next) => {
const origin = req.headers.origin ?? '';
if (/example\.com$/.test(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
}
next();
});
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'X-Accel-Buffering': 'no',
});
const t = setInterval(() => res.write(': ping\n\n'), 15_000);
req.on('close', () => clearInterval(t));
app.get('/health', async (_req, res) => {
await db.query('SELECT 1');
await redis.ping();
await fetch('https://payments.partner.com/status');
res.send('ok');
});
// LB: interval 5s, timeout 2s, unhealthy threshold 2