2.12 — Mini case study
Một tình huống rất hay gặp khi mới làm backend: người dùng đăng nhập thành công nhưng mọi trang sau đó đều báo 401 Unauthorized. Bài này lần theo request qua đúng năm chặng — trình duyệt, DNS, HTTPS, backend, database — và cho thấy cách loại trừ dần từng chặng thay vì đoán. Nguyên nhân cuối cùng hoá ra không nằm ở code xác thực chút nào, mà ở một thứ ít ai nghĩ tới khi mới học: đồng hồ của server lệch 12 phút, khiến token vừa cấp đã bị coi là hết hạn. Điều đáng học nhất là phương pháp: mỗi chặng đều có một cách kiểm tra riêng, và kiểm tra theo thứ tự tiết kiệm rất nhiều thời gian.
Mục tiêu bài học
Sau bài này bạn có thể:
- Lần theo một request qua năm chặng của hệ thống web.
- Dùng công cụ phù hợp để kiểm tra từng chặng.
- Loại trừ dần thay vì đoán nguyên nhân.
- Nhận ra những nguyên nhân nằm ngoài code.
Nội dung bài học
2.12.1 — Triệu chứng
Người dùng: "Tôi đăng nhập được, nhưng bấm vào bất kỳ menu nào
đều bị đẩy về trang đăng nhập."
Kiểm tra ban đầu:
- POST /api/auth/login -> 200 OK, trả về token
- GET /api/leads -> 401 Unauthorized
- Xảy ra với MỌI người dùng
- Mới bắt đầu sáng nay, hôm qua vẫn bình thường
Hai thông tin trong phần cuối đã thu hẹp phạm vi rất nhiều: mọi người dùng nghĩa là không phải vấn đề tài khoản cá nhân; mới bắt đầu hôm nay nghĩa là có gì đó vừa thay đổi.
2.12.2 — Năm chặng của một request
Nguyên tắc: kiểm tra từ ngoài vào trong, vì mỗi chặng loại trừ được là bớt một nửa phạm vi tìm kiếm.
2.12.3 — Chặng 1 và 2: trình duyệt, DNS, HTTPS
Mở DevTools, tab Network, xem request GET /api/leads:
Request URL: https://crm.company.com/api/leads
Status Code: 401 Unauthorized
Request Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs... <- token CÓ gửi đi
Hai kết luận ngay:
- DNS và HTTPS không phải vấn đề — request đã tới server và nhận được phản hồi. Nếu DNS sai, bạn sẽ thấy lỗi
ERR_NAME_NOT_RESOLVED; nếu chứng chỉ sai,ERR_CERT_*. - Frontend có gửi token — nếu thiếu header
Authorization, vấn đề nằm ở frontend, không phải backend.
Đây là bước kiểm tra nhanh nhất và loại trừ được hai chặng. Luôn bắt đầu từ đây (bài 2.5).
2.12.4 — Chặng 3: request có tới backend không?
# Gửi request trực tiếp, bỏ qua trình duyệt
curl -i https://crm.company.com/api/leads \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token",
error_description="The token expired at '09/24/2026 02:03:11'"
Đây là manh mối quyết định. Header WWW-Authenticate nói rõ lý do: token đã hết hạn.
Nhưng token vừa được cấp cách đây 30 giây. Nghĩa là thời gian hết hạn được tính sai — hoặc lúc cấp, hoặc lúc kiểm tra.
curl hữu ích ở đây vì nó loại bỏ mọi thứ của trình duyệt: cache, cookie, extension, CORS. Nếu curl cho kết quả khác trình duyệt thì vấn đề nằm ở phía trình duyệt.
2.12.5 — Chặng 4: backend xử lý thế nào
# Giai ma phan payload cua JWT (phan giua, ma hoa base64)
echo "eyJzdWIiOiIxMjMiLCJleHAiOjE3NjQ5NDY1OTF9" | base64 -d
{ "sub": "123", "exp": 1764946591, "iat": 1764945691 }
# Đổi timestamp sang thời gian đọc được
date -u -d @1764946591 # exp: 02:03:11 UTC
date -u -d @1764945691 # iat: 01:48:11 UTC (cấp lúc này)
date -u # BÂY GIỜ: 02:15:33 UTC <-- !!
Token được cấp lúc 01:48:11 với hạn 15 phút, tức hết hạn lúc 02:03:11. Nhưng "bây giờ" theo đồng hồ máy là 02:15:33 — muộn hơn 12 phút so với lúc token còn hạn.
Kiểm tra đồng hồ server:
timedatectl status
Local time: Wed 2026-09-24 02:15:33 UTC
Time zone: UTC (UTC, +0000)
System clock synchronized: no <-- KHÔNG đồng bộ
NTP service: inactive <-- NTP ĐÃ TẮT
Nguyên nhân gốc: dịch vụ NTP bị tắt trong một đợt cập nhật hệ thống đêm qua. Đồng hồ server trôi dần, và tới sáng nay nó lệch đủ để mọi token vừa cấp đã bị coi là hết hạn.
2.12.6 — Vì sao lệch đồng hồ gây ra chuyện này
JWT chứa exp là một mốc thời gian tuyệt đối (số giây từ 1970). Bên cấp và bên kiểm tra đều so nó với đồng hồ của mình. Nếu hai đồng hồ lệch nhau, kết luận sẽ khác nhau.
Server cấp token: dùng đồng hồ A -> exp = A + 15 phút
Server kiểm tra: dùng đồng hồ B
Nếu B nhanh hơn A 20 phút -> token vừa cấp đã "hết hạn"
Trong ca này, cả hai là cùng một server — nhưng đồng hồ trôi giữa lúc cấp và lúc kiểm tra, và độ trôi lớn hơn khoảng ClockSkew mặc định.
Sửa:
sudo timedatectl set-ntp true
sudo systemctl restart systemd-timesyncd
timedatectl status | grep synchronized # xác nhận: yes
Vấn đề biến mất ngay, không cần deploy lại gì.
Phòng ngừa: thêm kiểm tra đồng bộ thời gian vào health check, để lần sau hệ thống tự báo thay vì chờ người dùng phát hiện (bài 18.13).
2.12.7 — Bảng công cụ theo chặng
| Chặng | Câu hỏi | Công cụ |
|---|---|---|
| Trình duyệt | Request có được gửi đúng không? | DevTools → Network |
| DNS | Tên miền phân giải ra IP nào? | nslookup, dig |
| HTTPS | Chứng chỉ có hợp lệ không? | Ổ khoá trên thanh địa chỉ, openssl s_client |
| HTTP | Server trả về gì, kèm header nào? | curl -i |
| Backend | Xử lý tới đâu thì lỗi? | Log ứng dụng, breakpoint |
| Database | Truy vấn có chạy không? | Log truy vấn, profiler |
Thứ tự quan trọng. Bắt đầu từ chặng gần người dùng nhất và đi vào trong. Nhảy thẳng vào đọc code backend khi chưa biết request có tới đó không là cách tốn thời gian nhất.
2.12.8 — Rà lại code của bạn
Danh sách rà soát khi chẩn đoán lỗi web
- •Đã xem DevTools Network trước khi đọc code.
- •Đã xác nhận request có tới server và có kèm header cần thiết.
- •Đã dùng curl để loại trừ yếu tố trình duyệt.
- •Đã đọc kỹ thông điệp lỗi trong header phản hồi, không chỉ mã trạng thái.
- •Đã kiểm tra những thứ ngoài code: đồng hồ, biến môi trường, chứng chỉ.
- •Đã hỏi cái gì vừa thay đổi gần đây nhất.
- •Kiểm tra theo thứ tự từ ngoài vào trong, không nhảy cóc.
- •Sau khi sửa, đã thêm cảnh báo để lần sau hệ thống tự báo.
Bài tập áp dụng
Bài 1 — Lần theo một request
Mở DevTools trên một trang bất kỳ và ghi lại đầy đủ năm chặng của một request API.
Tiêu chí hoàn thành: bạn có số liệu cho từng chặng, và chỉ ra được chặng nào chiếm nhiều thời gian nhất — thường không phải chặng bạn đoán.
Gợi ý và lời giải — Bài 1
Gợi ý. Tab Network → bấm vào một request → tab Timing. Nó chia sẵn thời gian theo từng giai đoạn.
Lời giải — đọc bảng Timing:
Request: GET https://api.crm.vn/api/leads?page=1
Queueing 0,42 ms
Stalled 1,18 ms
DNS Lookup 24,00 ms <- chặng 2
Initial connection 48,00 ms <- chặng 2 (TCP)
SSL 31,00 ms <- chặng 2 (TLS, nằm trong Initial connection)
Request sent 0,21 ms <- chặng 3
Waiting (TTFB) 186,00 ms <- chặng 4: MÁY CHỦ XỬ LÝ
Content Download 12,00 ms <- chặng 5
---------
Total 271,81 ms
Ánh xạ sang năm chặng ở mục 2.12.2:
| Chặng | Trong DevTools | Thời gian | Tỉ lệ |
|---|---|---|---|
| 1. Trình duyệt chuẩn bị | Queueing + Stalled | 1,6 ms | 0,6% |
| 2. DNS + TCP + TLS | DNS + Initial connection | 72,0 ms | 26,5% |
| 3. Gửi request | Request sent | 0,2 ms | 0,1% |
| 4. Máy chủ xử lý | Waiting (TTFB) | 186,0 ms | 68,4% |
| 5. Nhận phản hồi | Content Download | 12,0 ms | 4,4% |
Ba điều bảng này nói ra:
1. Chặng 4 chiếm gần 70% — và đó là chặng duy nhất bạn kiểm soát được.
Waiting (TTFB) = thời gian từ lúc request tới máy chủ cho tới byte đầu tiên về
Nó gồm: định tuyến, middleware, truy vấn database, xử lý nghiệp vụ
-> đây là chỗ mọi kỹ thuật tối ưu backend tác động vào
2. Chặng 2 tốn 72 ms — nhưng chỉ ở request ĐẦU TIÊN.
# Gọi lại cùng endpoint ngay sau đó
DNS Lookup 0 ms <- đã có trong bộ nhớ đệm DNS
Initial connection 0 ms <- kết nối được dùng lại (keep-alive)
Waiting (TTFB) 182 ms
Content Download 11 ms
-------
Total 193 ms <- giảm 79 ms so với lần đầu
Đây là lý do đo một request đơn lẻ dễ gây hiểu lầm: request đầu tiên gánh toàn bộ chi phí thiết lập, những request sau thì không.
3. Và 12 ms tải nội dung cho một phản hồi 4,2 kB là chậm hơn bạn tưởng.
4,2 kB trên một kết nối bình thường: dưới 1 ms
12 ms nghĩa là phản hồi đến thành nhiều gói, hoặc mạng có độ trễ cao
-> nếu phản hồi là 400 kB thay vì 4 kB, con số này thành hàng trăm ms
-> và đó là lúc projection (chỉ lấy cột cần) trở nên quan trọng
Bốn chặng đầu đo được mà không cần trình duyệt:
curl -s -o /dev/null -w "\
dns: %{time_namelookup}s\n\
tcp: %{time_connect}s\n\
tls: %{time_appconnect}s\n\
ttfb: %{time_starttransfer}s\n\
tong: %{time_total}s\n" \
https://api.crm.vn/api/leads?page=1
dns: 0.024301s
tcp: 0.072118s
tls: 0.103447s
ttfb: 0.289512s
tong: 0.301776s
Lưu ý: các con số này CỘNG DỒN, không phải thời lượng từng phần.
thời gian TLS riêng = time_appconnect − time_connect = 31 ms
thời gian máy chủ = time_starttransfer − time_appconnect = 186 ms
Và một chặng mà DevTools không hiện ra, nhưng thường là nguyên nhân thật:
Waiting (TTFB) = 186 ms
Nhưng 186 ms đó gồm gì?
- middleware xác thực: ?
- truy vấn database: ?
- tuần tự hoá JSON: ?
DevTools không biết. Nó chỉ thấy "máy chủ mất 186 ms".
Để chia nhỏ chặng 4, cần đo từ phía máy chủ:
app.Use(async (ctx, next) =>
{
var sw = Stopwatch.StartNew();
await next();
ctx.Response.Headers["Server-Timing"] =
$"app;dur={sw.Elapsed.TotalMilliseconds:F1}";
});
Header Server-Timing hiện THẲNG trong tab Timing của DevTools
-> nối được số liệu phía máy chủ với số liệu phía trình duyệt
-> và đó là cách nhanh nhất để biết 186 ms đi đâu
Bài 2 — Giải mã JWT
Lấy một token thật, tách phần payload và giải mã base64. Đọc exp và iat rồi đổi sang thời gian.
Tiêu chí hoàn thành: bạn đọc được nội dung token mà không cần khoá bí mật, và rút ra được điều đó có nghĩa gì với dữ liệu bạn đặt trong token.
Gợi ý và lời giải — Bài 2
Gợi ý. JWT có ba phần ngăn bởi dấu chấm. Hai phần đầu chỉ là base64url — ai cũng đọc được.
Lời giải — một token mẫu:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4ODQyIiwibmFtZSI6Ik5ndXllbiB
WYW4gQW4iLCJ0ZW5hbnQiOiJtZWdhY29ycCIsImlhdCI6MTc5MDAwMDAwMCwibmJmIjoxNzkwMDAw
MDAwLCJleHAiOjE3OTAwMDA5MDB9.xsch3d9zSYqoCf_cI5kCcATAJkq7XA-7RQ3WHQuq4Zk
# Tách và giải mã phần payload (phần thứ hai)
echo "$TOKEN" | cut -d. -f2 | tr '_-' '/+' | base64 -d 2>/dev/null | jq
{
"sub": "8842",
"name": "Nguyen Van An",
"tenant": "megacorp",
"iat": 1790000000,
"nbf": 1790000000,
"exp": 1790000900
}
date -u -d @1790000000 +%FT%TZ # iat và nbf
date -u -d @1790000900 +%FT%TZ # exp
iat/nbf : 2026-09-21T14:13:20Z (issued at — lúc phát hành)
exp : 2026-09-21T14:28:20Z (expires — hết hạn)
Thời hạn sống: 900 giây = 15 phút
Và phần header, cũng đọc được như vậy:
{ "alg": "HS256", "typ": "JWT" }
Điều này có nghĩa gì — ba hệ quả:
1. JWT KHÔNG mã hoá. Nó chỉ được KÝ.
Chữ ký đảm bảo: nội dung KHÔNG BỊ SỬA
Chữ ký KHÔNG đảm bảo: nội dung được giữ kín
-> bất kỳ ai cầm token đều đọc được mọi claim trong đó
-> kể cả JavaScript trong trình duyệt, kể cả một proxy trung gian
2. Vì vậy, không đặt dữ liệu nhạy cảm vào token.
| Đặt được | Không đặt |
|---|---|
| Id người dùng | Số căn cư ớc, số thẻ |
| Tên hiển thị | Số điện thoại, địa chỉ |
| Mã tenant | Lương, hạn mức tín dụng |
| Vai trò | Mật khẩu hoặc băm mật khẩu |
| Quyền hạn ở mức thô | Ghi chú nội bộ về khách hàng |
Câu hỏi phân loại: "Nếu dòng này hiện trên màn hình người dùng,
có vấn đề gì không?"
3. Và sửa được không? Không — nhưng thử thì thấy rõ vì sao.
# Sửa "megacorp" thành "admin" trong payload rồi ghép lại
Máy chủ tính lại chữ ký từ header + payload MỚI bằng khoá bí mật
-> ra một chữ ký khác với chữ ký gửi lên
-> 401 Unauthorized
Muốn sửa mà vẫn hợp lệ thì phải có KHOÁ BÍ MẬT.
Ba trường iat, nbf, exp và vai trò của từng cái:
| Trường | Nghĩa | Máy chủ kiểm tra |
|---|---|---|
iat | Lúc phát hành | Thường chỉ để ghi nhận, và để thu hồi theo mốc thời gian |
nbf | Không hợp lệ trước thời điểm này | Token chưa tới giờ dùng → từ chối |
exp | Hết hạn sau thời điểm này | Token quá hạn → từ chối |
Cả ba đều là giây tính từ 1970-01-01 UTC (Unix epoch).
Chúng KHÔNG có múi giờ — luôn là UTC.
Vì sao thời hạn 15 phút, không phải 24 giờ:
JWT không thu hồi được. Đã phát ra là hợp lệ cho tới khi hết hạn.
Người dùng bị khoá tài khoản lúc 14:15
-> token phát lúc 14:13, hết hạn 14:28
-> họ vẫn truy cập được 13 phút nữa
Thời hạn càng dài, cửa sổ đó càng rộng.
Cách thường dùng:
access token 15 phút -> cửa sổ rủi ro nhỏ
refresh token 7–30 ngày, LƯU TRONG DATABASE -> thu hồi được ngay
Refresh token lưu trong database là chỗ bù lại điểm yếu của JWT: nó tra cứu được, nên khoá tài khoản có hiệu lực ngay ở lần làm mới token kế tiếp.
Và một mẹo nhỏ khi gỡ lỗi xác thực: xem token bằng một lệnh.
jwt() { echo "$1" | cut -d. -f2 | tr '_-' '/+' | base64 -d 2>/dev/null | jq; }
jwt "$TOKEN"
Dán vào jwt.io cũng được, NHƯNG:
-> đừng dán token thật của production vào một trang web
-> nó là thông tin đăng nhập đang còn hiệu lực
Bài 3 — Tái hiện lệch đồng hồ
Trên một máy ảo, tắt NTP và đặt đồng hồ lệch 20 phút, rồi thử đăng nhập vào ứng dụng có JWT.
Tiêu chí hoàn thành: bạn thấy lỗi xảy ra theo hai chiều khác nhau tuỳ đồng hồ nhanh hay chậm, và biết vì sao ClockSkew mặc định của .NET là 5 phút.
Gợi ý và lời giải — Bài 3
Gợi ý. Nghĩ xem máy nào lệch: máy phát token hay máy kiểm tra token. Hai trường hợp cho hai lỗi khác nhau.
Lời giải — dựng thí nghiệm:
# Trên máy ảo, tắt đồng bộ thời gian rồi đẩy đồng hồ đi 20 phút
sudo timedatectl set-ntp false
sudo date -s "+20 minutes"
timedatectl status | grep -E "Local time|synchronized"
Local time: Mon 2026-09-21 14:33:20 +07
System clock synchronized: no
Trường hợp A — máy KIỂM TRA token nhanh hơn 20 phút:
Máy phát: phát token lúc 14:13, exp = 14:28
Máy kiểm: đồng hồ chỉ 14:33
-> 14:33 > 14:28 -> token ĐÃ HẾT HẠN
401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token",
error_description="The token expired at '09/21/2026 14:28:20'"
Triệu chứng với người dùng: đăng nhập thành công,
rồi request ngay sau đó bị đẩy ra
-> vòng lặp đăng nhập
Trường hợp B — máy KIỂM TRA token chậm hơn 20 phút:
Máy phát: phát token lúc 14:13, nbf = 14:13
Máy kiểm: đồng hồ chỉ 13:53
-> 13:53 < 14:13 -> token CHƯA CÓ HIỆU LỰC
401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token",
error_description="The token is not valid before '09/21/2026 14:13:20'"
Triệu chứng: giống hệt trường hợp A với người dùng,
nhưng thông điệp lỗi hoàn toàn khác
Hai thông điệp lỗi này là manh mối quan trọng nhất:
"The token expired at ..." -> máy kiểm tra NHANH hơn máy phát
"The token is not valid before ..." -> máy kiểm tra CHẬM hơn máy phát
Và dấu hiệu chung cho cả hai: thời gian trong thông điệp lỗi
KHÔNG khớp với thời gian thật lúc bạn gặp lỗi.
-> nếu lỗi nói "hết hạn lúc 14:28" mà đồng hồ của bạn đang là 14:20,
thì có một đồng hồ đang sai.
Vì sao ClockSkew mặc định của .NET là 5 phút:
builder.Services.AddAuthentication().AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
ClockSkew = TimeSpan.FromMinutes(5), // mặc định
};
});
Trong hệ phân tán, đồng hồ các máy KHÔNG BAO GIỜ khớp tuyệt đối.
NTP giữ sai lệch ở mức mili giây tới vài chục mili giây trong điều kiện tốt,
nhưng máy ảo bị tạm dừng, máy vừa khởi động, hoặc NTP hỏng có thể lệch nhiều hơn.
5 phút là khoảng đệm đủ rộng để chịu được lệch thực tế,
đủ hẹp để không làm mất ý nghĩa của thời hạn token.
Với thí nghiệm lệch 20 phút: 5 phút đệm không đủ -> vẫn lỗi
Với lệch 2 phút: đệm hấp thụ hết -> không ai nhận ra có vấn đề
Ba cấu hình liên quan, và cách chọn:
| Cấu hình | Khi nào |
|---|---|
ClockSkew = TimeSpan.Zero | Khi mọi máy chắc chắn đồng bộ NTP, và bạn muốn thời hạn chính xác |
ClockSkew = 5 phút (mặc định) | Phần lớn trường hợp |
ClockSkew lớn hơn 5 phút | Gần như luôn là dấu hiệu che giấu một vấn đề về đồng hồ |
Đặt ClockSkew = Zero với access token 15 phút:
một máy lệch 30 giây -> token hết hạn sớm 30 giây so với dự kiến
-> người dùng gặp lỗi ngẫu nhiên, khó tái hiện
Cách phòng đúng: sửa đồng hồ, không nới ClockSkew.
sudo timedatectl set-ntp true
timedatectl status
System clock synchronized: yes
NTP service: active
# Trong Kubernetes, node đồng bộ thời gian — pod dùng chung đồng hồ của node
# Nên vấn đề thường nằm ở NODE, không ở container
Và một cách phát hiện sớm, trước khi người dùng báo lỗi:
// Ghi độ lệch giữa thời gian phát token và thời gian máy chủ hiện tại
o.Events = new JwtBearerEvents
{
OnTokenValidated = ctx =>
{
var iat = ctx.Principal?.FindFirst("iat")?.Value;
if (long.TryParse(iat, out var giay))
{
var lech = (DateTimeOffset.UtcNow - DateTimeOffset.FromUnixTimeSeconds(giay)).TotalSeconds;
if (Math.Abs(lech) > 60)
ctx.HttpContext.RequestServices
.GetRequiredService<ILogger<Program>>()
.LogWarning("Lệch đồng hồ nghi ngờ: {Lech} giây", lech);
}
return Task.CompletedTask;
}
};
Cảnh báo này xuất hiện TRƯỚC khi độ lệch vượt ClockSkew
-> bạn sửa NTP trong lúc hệ thống vẫn chạy bình thường,
thay vì lúc mọi người đang không đăng nhập được
Và đây là ý chung của mục 2.12.6: lệch đồng hồ không gây lỗi từ từ — nó hoạt động hoàn hảo cho tới khi vượt ngưỡng, rồi hỏng hoàn toàn. Một cảnh báo ở ngưỡng thấp hơn là cách duy nhất để thấy nó đang tới.
Tự kiểm tra
Frequently asked questions
Vì sao nên kiểm tra từ ngoài vào trong?
Vì mỗi chặng loại trừ được là bớt một nửa phạm vi tìm kiếm. Nhảy thẳng vào đọc code backend khi chưa biết request có tới đó không là cách tốn thời gian nhất.
DevTools Network cho biết những gì trong ca này?
Rằng DNS và HTTPS không phải vấn đề vì request đã tới server và nhận được phản hồi, và rằng frontend có gửi header Authorization. Hai kết luận đó loại trừ được hai chặng đầu ngay lập tức.
Vì sao dùng curl thay vì chỉ thử trên trình duyệt?
Vì curl loại bỏ mọi yếu tố của trình duyệt như cache, cookie, extension và CORS. Nếu curl cho kết quả khác trình duyệt thì vấn đề nằm ở phía trình duyệt chứ không phải server.
Vì sao lệch đồng hồ làm token vừa cấp đã hết hạn?
Vì JWT chứa exp là mốc thời gian tuyệt đối, và bên kiểm tra so nó với đồng hồ của mình. Nếu đồng hồ trôi nhanh hơn giữa lúc cấp và lúc kiểm tra, và độ trôi lớn hơn khoảng dung sai cho phép, token sẽ bị coi là hết hạn.
Thông tin nào trong triệu chứng ban đầu giúp thu hẹp phạm vi nhất?
Rằng lỗi xảy ra với mọi người dùng, nên không phải vấn đề tài khoản cá nhân, và rằng nó mới bắt đầu hôm nay, nên có gì đó vừa thay đổi. Hai thông tin đó hướng ngay tới thay đổi hệ thống chứ không phải bug code.
Nên làm gì sau khi sửa xong sự cố kiểu này?
Thêm kiểm tra đồng bộ thời gian vào health check, để lần sau hệ thống tự báo thay vì chờ người dùng phát hiện. Mỗi sự cố nên để lại một cảnh báo mới.
Kết luận
Ba điều đáng nhớ nhất:
- Kiểm tra từ ngoài vào trong. DevTools trư ớc, code sau.
- Đọc kỹ thông điệp lỗi, không chỉ mã trạng thái — nó thường nói thẳng nguyên nhân.
- Nguyên nhân có thể nằm ngoài code: đồng hồ, biến môi trường, chứng chỉ.
Tham khảo
Điều hướng
- Bài trước: 2.10 — Mở rộng và đào sâu
- Bài tiếp theo: 2.12 — Ví dụ thực tế nhanh
- Về module: Trang mục lục