Web 22/09/2026 6 phút

WebSocket: HTTP nâng cấp thành kênh hai chiều — mổ xẻ cái bắt tay 101

WebSocket không phải một giao thức tách rời HTTP mà mọc lên TỪ HTTP: một request GET với header Upgrade, đáp lại là 101 Switching Protocols chứ không phải 200. Bài này tự dựng cả server lẫn client WebSocket bằng socket thuần, đo output thật: cách tính Sec-WebSocket-Accept từ key + GUID, và frame hai chiều mà frame từ client bắt buộc mask.

Web 22/09/2026 6 phút

Header bảo mật HTTP: HSTS, CSP, X-Frame-Options — mỗi dòng chặn một kiểu tấn công

Một dòng header có thể chặn cả một lớp tấn công. Bài này xem các header bảo mật THẬT mà chính blog này gửi, rồi dùng Chromium thật nhúng hai iframe — một trang có X-Frame-Options DENY, một không — để thấy trình duyệt thực sự từ chối hiển thị trang DENY: 'Refused to display ... X-Frame-Options to deny'. Không phải mô tả, là trình duyệt thi hành.

Lập trình 22/09/2026 6 phút

Nén trong HTTP: vì sao trang web tải nhanh gấp 10 lần mà bạn không thấy gì

Mỗi lần trình duyệt tải một trang, nó và server âm thầm thương lượng nén qua header Accept-Encoding và Content-Encoding. Bài này đo thật trên coffeecode.vn: trang chủ 245KB tải về chỉ còn 25KB nhờ gzip (nhỏ 9.8 lần). Và so gzip với brotli trên chính HTML đó — brotli nhỏ hơn gzip 24%. Cơ chế thương lượng, vì sao Vary: Accept-Encoding là bắt buộc, và chỉ nén text.

Lập trình 22/09/2026 5 phút

HTTP keep-alive: vì sao 500 request chỉ nên mở 1 kết nối, không phải 500

Bài 1 cho thấy bắt tay TCP tốn một RTT mỗi kết nối. Keep-alive giải đúng chuyện đó ở tầng HTTP: giữ kết nối mở để nhiều request dùng chung, bắt tay đúng một lần. Bài này chạy thật trong Go và đếm kết nối TCP thực: 500 request với keep-alive mở đúng 1 kết nối và nhanh hơn 3,9 lần so với tắt keep-alive mở 500 — cùng những cái bẫy vô tình làm mất keep-alive.

Lập trình 22/09/2026 5 phút

Connection pool: vì sao pool mặc định 2 làm bạn mở 546 kết nối cho 2000 request

Keep-alive tái dùng một kết nối cho các request tuần tự, nhưng khi nhiều request chạy song song, mỗi luồng cần một kết nối cùng lúc — đó là việc của connection pool. Bài này chạy thật trong Go: 2000 request song song 50 luồng với pool mặc định (2) mở tới 546 kết nối vì churn, còn pool đủ lớn chỉ mở 50 và nhanh hơn. Giải thích cách chọn kích cỡ pool đúng.

Lập trình 22/09/2026 9 phút

Hợp đồng lỗi của API: đo thật — trả 500 cho lỗi của client biến 300 request sai thành 900 request thừa và 63% báo động giả

Cùng một lõi nghiệp vụ, ba cách trả lỗi: cứ lỗi là 500 kèm err.Error(), mọi thứ đều 200 kèm trường success, và RFC 9457 Problem Details với mã đúng loại. Đo bằng một client có chính sách retry chuẩn — retry 5xx, không retry 4xx — trên 1.000 request có 300 request sai dữ liệu: bản 500 nhận 1.900 request thay vì 1.000, tỉ lệ 5xx trên server lên 63,2% dù server hoàn toàn khoẻ, và mỗi request lỗi mất 290 ms thay vì 0,03 ms. Bản mọi-thứ-đều-200 thì ngược lại: 300 lỗi mang mã 200 và server chết vẫn xanh trên biểu đồ. Kèm chuyện bản 500 lộ tên bảng, tên ràng buộc và địa chỉ database ra ngoài.