JWT là gì? Mã thông báo Web JSON được giải thích bằng một ví dụ hoạt động
JWT cho phép máy chủ tin cậy một yêu cầu mà không cần tra cứu bất cứ điều gì. Xây dựng một cái từ đầu, cố gắng giả mạo nó và xem nó thất bại, sau đó tìm hiểu khi nào mã thông báo đánh bại các phiên và cách sử dụng chúng một cách an toàn.
- JWT là một mã thông báo nhỏ gọn có chữ ký gồm ba phần: tiêu đề, tải trọng và chữ ký.
- Chữ ký chứng minh mã thông báo chưa bị thay đổi nên máy chủ có thể tin cậy nó mà không cần tra cứu.
- Tải trọng này bất kỳ ai cũng có thể đọc được, vì vậy đừng bao giờ đặt bí mật vào đó.
- Mã thông báo khó thu hồi, vì vậy hãy giữ chúng trong thời gian ngắn và xác minh chúng bằng thư viện đáng tin cậy.
Sau khi bạn đăng nhập, làm thế nào máy chủ biết rằng mỗi yêu cầu sau đó thực sự là của bạn? Một câu trả lời phổ biến là Mã thông báo Web JSON hay JWT, thường được phát âm là “jot”. Đó là một đoạn dữ liệu nhỏ có chữ ký mà khách hàng gửi với mỗi yêu cầu và máy chủ có thể kiểm tra nó mà không cần chạm vào cơ sở dữ liệu.
Cách nhanh nhất để hiểu JWT là xây dựng một JWT và sau đó thử phá vỡ nó. Chúng tôi đã làm điều đó chỉ bằng cách sử dụng thư viện chuẩn của Python, trên Python 3.13 và kết quả đầu ra bên dưới là từ lần chạy đó. Mã này dành cho việc học. Trong ứng dụng thực tế, hãy sử dụng thư viện được bảo trì tốt vì các chi tiết xác minh rất dễ bị sai.
JWT là gì?
JWT là một tiêu chuẩn mở, được định nghĩa trong RFC 7519, để chuyển các yêu cầu giữa hai bên dưới dạng một chuỗi nhỏ gọn. Xác nhận quyền sở hữu chỉ đơn giản là một tuyên bố, chẳng hạn như “ID của người dùng này là 42”. Vì mã thông báo đã được ký nên người nhận có thể xác nhận ai đã phát hành mã thông báo đó và không ai thay đổi mã thông báo đó.
Hãy nghĩ về một chiếc vòng tay lễ hội. Nhân viên tại cổng kiểm tra vé của bạn một lần và đưa cho bạn một chiếc vòng tay khó làm giả. Sau đó, mỗi gian hàng chỉ cần nhìn ban nhạc mà không cần gọi điện tới phòng bán vé. JWT hoạt động theo cách tương tự đối với API.
Cách đăng nhập JWT hoạt động
- Người dùng gửi tên người dùng và mật khẩu đến điểm cuối đăng nhập.
- Máy chủ kiểm tra chúng và tạo mã thông báo đã ký.
- Khách hàng lưu trữ mã thông báo.
- Mỗi yêu cầu sau này đều bao gồm nó, thường ở tiêu đề:
Authorization: Bearer <token>. - Máy chủ xác minh chữ ký và thời hạn sử dụng, sau đó đọc các khiếu nại.
Lợi ích chính nằm ở bước 5. Máy chủ không phải tra cứu phiên, thuận tiện khi nhiều dịch vụ hoặc máy chủ cần kiểm tra cùng một token. Nếu bạn chưa quen với API, hãy bắt đầu với API là gì.
Ba phần của JWT
JWT trông giống như văn bản ngẫu nhiên, nhưng nó là ba phần được mã hóa Base64URL được phân tách bằng dấu chấm. Đây là một cái chúng tôi đã tạo:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiI0MiIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzkzNTAwMDAwLCJleHAiOjE3OTM1MDA5MDB9
.7YfUDH_T-iDh8bMmUT8mmKYwOstzT8Ty--DTTAmQGWM
Chúng tôi đã thêm ngắt dòng để dễ đọc hơn. Giải mã hai phần đầu tiên cho JSON đơn giản:
Header: {"alg":"HS256","typ":"JWT"}
Payload: {"sub":"42","role":"user","iat":1793500000,"exp":1793500900}
| phần | Chứa | Mục đích |
|---|---|---|
| tiêu đề | Loại mã thông báo và thuật toán ký | Nói cách xác minh mã thông báo |
| Tải trọng | Khiếu nại về người dùng hoặc phiên | Thông tin thực tế |
| Chữ ký | Hàm băm của hai phần đầu tiên, sử dụng khóa | Chứng minh tính toàn vẹn và nguồn gốc |
Yêu cầu tiêu chuẩn
| Yêu cầu | Tên | Ý nghĩa |
|---|---|---|
phụ |
Chủ đề | Mã thông báo nói về ai, thường là ID người dùng |
là |
Tổ chức phát hành | Ai đã tạo mã thông báo |
kiểm toán |
khán giả | Mã thông báo dành cho ai |
điểm kinh nghiệm |
Hết hạn | Khi mã thông báo ngừng hợp lệ |
đó |
Phát hành tại | Khi nó được tạo ra |
nbf |
Không phải trước đây | Khi nó bắt đầu có hiệu lực |
jti |
ID JWT | ID duy nhất cho mã thông báo này |
Bạn cũng có thể thêm các xác nhận quyền sở hữu tùy chỉnh, như role. Thời gian là dấu thời gian Unix, tính bằng giây. Giữ tải trọng nhỏ vì mã thông báo sẽ di chuyển theo mọi yêu cầu.
Tự mình xây dựng một cái
Việc tạo mã thông báo bao gồm việc mã hóa hai phần JSON, sau đó ký chúng bằng một bí mật bằng cách sử dụng HMAC-SHA256:
import base64, hashlib, hmac, json
SECRET = b"demo-secret-do-not-use-in-production"
def b64url(data):
return base64.urlsafe_b64encode(data).rstrip(b"=").decode()
def sign(message):
return b64url(hmac.new(SECRET, message.encode(), hashlib.sha256).digest())
def create_token(payload):
header = {"alg": "HS256", "typ": "JWT"}
parts = [
b64url(json.dumps(header, separators=(",", ":")).encode()),
b64url(json.dumps(payload, separators=(",", ":")).encode()),
]
message = ".".join(parts)
return message + "." + sign(message)
Quá trình xác minh hoạt động bằng cách tính toán lại chữ ký và so sánh nó với chữ ký trong mã thông báo. Chỉ người có bí mật mới có thể tạo ra bí mật phù hợp:
def verify_token(token, now):
header, payload, signature = token.split(".")
expected = sign(header + "." + payload)
if not hmac.compare_digest(signature, expected):
raise ValueError("bad signature")
claims = json.loads(b64url_decode(payload))
if claims["exp"] < now:
raise ValueError("token expired")
return claims
Mã thông báo hợp lệ đã trả lại yêu cầu của nó như mong đợi. compare_digest được sử dụng vì nó chạy trong thời gian không đổi, giúp tránh rò rỉ thông tin do chênh lệch thời gian.
Cố gắng can thiệp vào nó
Giả sử kẻ tấn công giải mã tải trọng, thay đổi "role":"user" thành "role":"admin", mã hóa lại và giữ chữ ký cũ. Chúng tôi đã thử điều này cùng với hai cuộc tấn công khác:
| Cố gắng | kết quả |
|---|---|
| Đã thay đổi vai trò thành quản trị viên | chữ ký xấu |
| Đã sử dụng mã thông báo 1 giây sau khi hết hạn | mã thông báo đã hết hạn |
Đặt "alg":"none" và xóa chữ ký |
chữ ký xấu |
Nỗ lực cuối cùng đó nhằm vào một điểm yếu lịch sử thực sự. Một số thư viện từng tin cậy tiêu đề riêng của mã thông báo, vì vậy kẻ tấn công có thể chỉ cần tuyên bố rằng không cần chữ ký. Mã của chúng tôi luôn sử dụng một thuật toán cố định, đó là lý do tại sao nó bị từ chối. Trong thư viện thực, hãy luôn chỉ định các thuật toán bạn chấp nhận.
Đã ký, không được mã hóa
Đây là điểm bị hiểu lầm nhiều nhất về JWT. Mã thông báo giả mạo của chúng tôi đã bị từ chối nhưng nội dung của nó vẫn hoàn toàn có thể đọc được:
{"sub":"42","role":"admin","iat":1793500000,"exp":1793500900}
Base64URL là một mã hóa, không phải mã hóa và bất kỳ ai cũng có thể đảo ngược nó mà không cần khóa. Chữ ký ngăn mọi người thay đổi dữ liệu chứ không ngăn đọc dữ liệu đó. Vì vậy, đừng bao giờ đặt mật khẩu, số thẻ hoặc dữ liệu cá nhân riêng tư vào tải trọng JWT. Nếu nội dung phải bị ẩn, hãy sử dụng mã thông báo được mã hóa (JWE) hoặc chỉ giữ dữ liệu trên máy chủ.
HS256 so với RS256
| Khía cạnh | HS256 | RS256 hoặc ES256 |
|---|---|---|
| Loại | đối xứng | Bất đối xứng |
| Phím | Một bí mật chung | Khóa riêng ký hiệu, khóa chung xác minh |
| Ai có thể tạo mã thông báo | Bất cứ ai nắm giữ bí mật | Chỉ người giữ khóa riêng |
| Tốt nhất cho | Một dịch vụ hoặc một nhóm nhỏ đáng tin cậy | Nhiều dịch vụ, bên thứ ba, nhà cung cấp danh tính |
Với việc ký bất đối xứng, các dịch vụ khác có thể xác minh mã thông báo mà không thể tạo ra mã thông báo của riêng chúng, điều này sẽ hạn chế thiệt hại nếu một mã bị xâm phạm.
JWT so với phiên
JWT thường được trình bày như một sự thay thế hiện đại cho các phiên. Trong thực tế, mỗi cái đều có sự đánh đổi:
| Khía cạnh | Phiên máy chủ | JWT |
|---|---|---|
| Nơi nhà nước sống | Trên máy chủ | Trong mã thông báo |
| Tra cứu theo từng yêu cầu | Thông thường | Không cần thiết |
| Đăng xuất hoặc thu hồi | Dễ dàng, xóa phiên | Cứng trước khi hết hạn |
| Kích thước theo yêu cầu | ID nhỏ | Mã thông báo lớn hơn (của chúng tôi là 161 ký tự) |
| Trên nhiều dịch vụ | Cần lưu trữ chia sẻ | Mỗi người có thể xác minh nó trực tiếp |
| Thay đổi quyền | Áp dụng ngay lập tức | Mã thông báo cũ vẫn có hiệu lực cho đến khi hết hạn |
Đối với trang web được hiển thị trên máy chủ truyền thống, cookie phiên thường đơn giản và an toàn hơn. JWT có xu hướng có ý nghĩa hơn đối với các API được sử dụng bởi một số dịch vụ hoặc đối với ứng dụng khách trên thiết bị di động.
Mẹo: Đừng chọn JWT chỉ vì nó nghe có vẻ không trạng thái. Nhiều hệ thống thực tế thêm danh sách từ chối hoặc kiểm tra cơ sở dữ liệu để hỗ trợ đăng xuất, điều này mang lại sự tra cứu mà JWT vốn muốn tránh.
Nơi lưu trữ mã thông báo trong trình duyệt
| Vị trí | Rủi ro XSS | Rủi ro CSRF | Ghi chú |
|---|---|---|---|
lưu trữ cục bộ |
Cao, vì script có thể đọc được | Thấp | Đơn giản nhưng có thể tiếp xúc với bất kỳ tập lệnh được chèn nào |
| HttpOnly cookie | Thấp hơn, vì script không thể đọc được | Cần bảo vệ | Sử dụng Secure và SameSite |
| Biến trong bộ nhớ | Hạ xuống | Thấp | Mất khi làm mới, vì vậy nó cần một luồng làm mới |
Nhiều hướng dẫn bảo mật ưu tiên cookie HttpOnly, Secure, SameSite cho ứng dụng web. Dù bạn chọn cách nào, hãy luôn sử dụng HTTPS. Để gửi mã thông báo từ JavaScript, hãy xem Hướng dẫn API tìm nạp JavaScript của chúng tôi.
Làm mới mã thông báo
Thời hạn sử dụng ngắn sẽ hạn chế thiệt hại do mã thông báo bị đánh cắp, nhưng không ai muốn đăng nhập sau mỗi 15 phút. Giải pháp thông thường sử dụng hai mã thông báo:
- Mã thông báo truy cập: tồn tại trong thời gian ngắn, chẳng hạn như số phút và được gửi cùng với mọi yêu cầu API.
- Mã thông báo làm mới: tồn tại lâu hơn, được lưu trữ cẩn thận hơn và chỉ được sử dụng để nhận mã thông báo truy cập mới.
Máy chủ theo dõi các mã thông báo làm mới, do đó, nó có thể thu hồi chúng, giúp bạn đăng xuất một cách thiết thực. Xoay chúng trong mỗi lần sử dụng cũng giúp bạn phát hiện hành vi trộm cắp vì mã thông báo cũ bị đánh cắp sẽ được phát lại.
Những lỗi bảo mật thường gặp
- Giải mã mà không cần xác minh. Việc đọc tải trọng không làm cho nó trở nên đáng tin cậy. Luôn kiểm tra chữ ký.
- Chấp nhận bất kỳ thuật toán nào. Đặt danh sách rõ ràng các thuật toán được phép.
- Sử dụng bí mật yếu. Bí mật ngắn có thể bị bẻ khóa ngoại tuyến. Sử dụng một giá trị ngẫu nhiên dài và giữ nó ngoài tầm kiểm soát nguồn.
- Bỏ qua thời hạn sử dụng. Token không có
expcó thể hoạt động mãi mãi nếu bị đánh cắp. - Không kiểm tra
issvàaud. Nếu không, mã thông báo được cấp cho một dịch vụ có thể được dịch vụ khác chấp nhận. - Tin vào các tuyên bố cũ. Vai trò bên trong mã thông báo có thể lỗi thời cho đến khi hết hạn.
- Mã thông báo ghi nhật ký. Bất kỳ ai đọc nhật ký của bạn đều có thể sử dụng lại chúng.
- Không kiểm tra các đường dẫn lỗi. Thêm các thử nghiệm cho các mã thông báo đã hết hạn và đã sửa đổi cũng như các mã thông báo hợp lệ. Hướng dẫn kiểm tra API bằng Postman của chúng tôi có thể giúp ích.
Lời kết
JWT là dữ liệu đã được ký mà máy chủ có thể tin cậy mà không cần tra cứu, không phải là vùng chứa bí mật và không phải là bản nâng cấp tự động qua các phiên. Sử dụng thời hạn sử dụng ngắn, xác minh mọi thứ bằng thư viện được duy trì và loại bỏ dữ liệu riêng tư khỏi tải trọng. Để tự mình xem, hãy chạy một tập lệnh nhỏ như của chúng tôi, thay đổi một ký tự của mã thông báo và xem quá trình xác minh không thành công.
Câu hỏi thường gặp
JWT dùng để làm gì?
JWT chủ yếu được sử dụng để xác thực và ủy quyền trong API. Sau khi đăng nhập, khách hàng sẽ gửi mã thông báo với mỗi yêu cầu và máy chủ sẽ xác minh nó để xác định người dùng.
JWT có được mã hóa không?
Thường thì không. JWT tiêu chuẩn được ký và mã hóa để bất kỳ ai cũng có thể đọc được tải trọng của nó. Chữ ký chỉ ngăn chặn những thay đổi. Mã thông báo được mã hóa sử dụng định dạng liên quan được gọi là JWE.
JWT nên tồn tại trong bao lâu?
Mã thông báo truy cập thường tồn tại trong thời gian ngắn, thường là vài phút thay vì vài ngày. Ghép nối chúng với mã thông báo làm mới để người dùng không phải đăng nhập liên tục.
JWT có thể bị thu hồi không?
Không phải tự nó, vì nó vẫn có hiệu lực cho đến khi hết hạn. Việc thu hồi yêu cầu theo dõi phía máy chủ, chẳng hạn như danh sách từ chối, loại bỏ một số lợi ích không có trạng thái.
JWT có tốt hơn phiên không?
Không phải lúc nào cũng tốt hơn. Phiên thu hồi đơn giản hơn và phù hợp với nhiều trang web, trong khi JWT phù hợp với các API và dịch vụ cần xác minh danh tính một cách độc lập.
Tiếp tục học hỏi
Cần trợ giúp về kiểm tra, WordPress hoặc SEO?
Chúng tôi giúp các nhóm phát triển phần mềm tốt hơn và phát triển trang web của họ. Hãy cho chúng tôi biết bạn đang làm gì và chúng tôi sẽ đề xuất bước tiếp theo rõ ràng.
Thêm hướng dẫn về thử nghiệm, AI và phát triển hiện đại
Bạn thích bài viết này? Chọn một chủ đề và chuyển ngay sang phần hướng dẫn mới nhất của chúng tôi.
Giải thích về ảo giác AI: Tại sao các mô hình ngôn ngữ lại tạo nên mọi thứ và cách giảm thiểu nó
Ảo giác AI đã giải thích: chúng là gì, tại sao mô hình ngôn ngữ tạo ra chúng, các loại phổ biến, cách giảm thiểu chúng bằng cách căn cứ và nhắc nhở …
Đọc bài viết →DevOpsGiải thích về các biến môi trường: Tệp .env, bí mật và cấu hình được thực hiện đúng
Các biến môi trường được giải thích bằng các ví dụ Python mà chúng tôi đã chạy: đọc và thiết lập chúng, tại sao mọi giá trị đều là một chuỗi, tệp .e…
Đọc bài viết →Phát triển phần mềmGiải thích về giới hạn tỷ lệ API: Thuật toán, tiêu đề và xử lý lỗi 429
Giới hạn tốc độ API được giải thích bằng mô phỏng mà chúng tôi đã chạy: nhóm mã thông báo, cửa sổ cố định, cửa sổ trượt, 429 phản hồi, tiêu đề giới …
Đọc bài viết →Tự động hóa kiểm thửChế giễu bằng Python: unittest.mock, patch và những sai lầm khiến bài kiểm tra nói dối
Mô phỏng bằng Python với unittest.mock, đã được thử nghiệm: Mock và return_value, side_effect, vá lỗi nơi sử dụng tên, thông số kỹ thuật và thông số…
Đọc bài viết →Kiểm thử phần mềmGiải thích về phạm vi bảo hiểm của mã: Phạm vi tuyến so với chi nhánh và ý nghĩa thực sự 100%
Phạm vi bảo hiểm mã được giải thích bằng cách chạy phạm vi bảo hiểm thực tế: phạm vi bảo hiểm dòng, chi nhánh và điều kiện, đọc báo cáo, lý do tại s…
Đọc bài viết →Cơ sở dữ liệu & SQLDELETE vs TRUNCATE vs DROP trong SQL: Sự khác biệt, khôi phục và thời điểm sử dụng mỗi loại
DELETE vs TRUNCATE vs DROP được giải thích bằng SQL đã được thử nghiệm: mỗi loại loại bỏ, khôi phục, kích hoạt, đặt lại danh tính, tốc độ và Postgre…
Đọc bài viết →Cơ sở dữ liệu & SQLGiải thích về Chế độ xem SQL: Tạo, sử dụng và tránh những cạm bẫy, kèm theo ví dụ
Chế độ xem SQL được giải thích bằng các truy vấn chúng tôi đã chạy: tạo chế độ xem, kết quả trực tiếp, ẩn cột, hiệu suất, chế độ xem có thể cập nhật…
Đọc bài viết →Phát triển phần mềmGiao diện TypeScript so với loại: Sự khác biệt thực sự, được thử nghiệm bằng trình biên dịch
Giao diện TypeScript so với loại, được kiểm tra bằng trình biên dịch thực: cả hai có thể làm gì, chỉ một người có thể làm gì, hợp nhất khai báo, mở …
Đọc bài viết →Phát triển phần mềmGiải thích về Python *args và **kwargs: Hàm linh hoạt với ví dụ rõ ràng
Python *args và **kwargs được giải thích bằng mã chúng tôi đã chạy: đóng gói và giải nén, thứ tự tham số, đối số chỉ từ khóa và chỉ vị trí, trình tr…
Đọc bài viết →Phát triển phần mềmHàm Lambda của Python: Cú pháp, cách sử dụng thực tế và khi nào không nên sử dụng chúng
Các hàm lambda của Python được giải thích bằng mã chúng tôi đã chạy: cú pháp, sắp xếp bằng khóa, bản đồ và bộ lọc, các phần đóng, bẫy liên kết muộn …
Đọc bài viết →Trí tuệ nhân tạoĐại lý AI là gì? Cách chúng hoạt động, với vòng lặp tác nhân đơn giản, bạn có thể chạy
Tác nhân AI là gì? Hướng dẫn đơn giản về vòng lặp tác nhân, công cụ, bộ nhớ và lan can, với một vòng lặp Python nhỏ mà chúng tôi đã chạy, những rủi …
Đọc bài viết →DevOpsGiám sát và Khả năng quan sát: Sự khác biệt thực sự, với nhật ký, số liệu và dấu vết
Giải thích về giám sát và khả năng quan sát: lỗi đã biết và chưa biết, nhật ký, số liệu và dấu vết, hướng dẫn về sự cố thanh toán, tín hiệu vàng, Op…
Đọc bài viết →DevOpsDocker Volumes vs Bind Mounts: Duy trì dữ liệu vùng chứa đúng cách
Giải thích về khối lượng Docker và liên kết gắn kết: tại sao dữ liệu vùng chứa biến mất, khối lượng được đặt tên, liên kết gắn kết, tmpfs, ví dụ về …
Đọc bài viết →Tự động hóa kiểm thửTDD vs BDD: Key Differences, One Feature Built Both Ways and When to Use Each
TDD và BDD được giải thích bằng một tính năng giảm giá được xây dựng theo cả hai cách: tái cấu trúc màu đỏ-xanh với mã chúng tôi đã chạy, kịch bản C…
Đọc bài viết →Kiểm thử phần mềmKiểm tra chấp nhận của người dùng (UAT): Quy trình, danh sách kiểm tra và ví dụ thực tế
Giải thích về thử nghiệm chấp nhận của người dùng: ai chạy nó, nó khác với QA như thế nào, quy trình bảy bước, mẫu trường hợp thử nghiệm UAT, danh s…
Đọc bài viết →Cơ sở dữ liệu & SQLGiải thích về các giá trị NULL của SQL: IS NULL, COALESCE, NULLIF và những cái bẫy cần tránh
Các giá trị SQL NULL được giải thích bằng các truy vấn chúng tôi đã chạy: logic ba giá trị, IS NULL, COALESCE, NULLIF, cách tổng hợp, kết hợp và sắp…
Đọc bài viết →Cơ sở dữ liệu & SQLCâu lệnh SQL CASE WHEN: Cú pháp, ví dụ thực tế và các lỗi thường gặp
TRƯỜNG HỢP SQL KHI được giải thích bằng các truy vấn mà chúng tôi đã chạy: các biểu mẫu đơn giản và được tìm kiếm, thứ tự điều kiện, các thủ thuật S…
Đọc bài viết →Phát triển phần mềmJWT là gì? Mã thông báo Web JSON được giải thích bằng một ví dụ hoạt động
JWT là gì? Mã thông báo Web JSON đã giải thích: ba phần, mã thông báo được xây dựng và giả mạo trong mã chúng tôi đã chạy, JWT so với phiên, lưu trữ…
Đọc bài viết →Phát triển phần mềmGiải thích về vòng lặp sự kiện JavaScript: Ngăn xếp cuộc gọi, Microtask và bộ hẹn giờ kèm ví dụ
Vòng lặp sự kiện JavaScript được giải thích bằng mã chúng tôi đã chạy: ngăn xếp cuộc gọi, hàng đợi tác vụ và vi nhiệm, tại sao setTimeout 0 không di…
Đọc bài viết →Phát triển phần mềmGiải thích về trình tạo và năng suất của Python: Tiết kiệm bộ nhớ bằng các ví dụ thực tế
Trình tạo và lợi nhuận Python được giải thích bằng mã chúng tôi đã chạy: cách chúng tạm dừng và tiếp tục, đo mức tiết kiệm bộ nhớ, quy trình, chuỗi …
Đọc bài viết →Trí tuệ nhân tạoNhúng là gì? Giải thích sự tương đồng về vectơ và Cosine một cách đơn giản
nhúng là gì? Hướng dẫn bằng ngôn ngữ đơn giản về vectơ, độ tương tự cosine và tìm kiếm ngữ nghĩa, với một ví dụ nhỏ mà chúng tôi đã chạy, các cách s…
Đọc bài viết →DevOpsTriển khai Blue-Green và Canary: Sự khác biệt, sự đánh đổi và cách lựa chọn
Giải thích về triển khai Blue-green và Canary: cách hoạt động của từng loại, chi phí, rủi ro và khôi phục, nhóm người dùng ổn định mà chúng tôi đã t…
Đọc bài viết →Phát triển phần mềmGit merge vs rebase: khác biệt, ví dụ và khi nào dùng cái nào
Git merge vs rebase được giải thích bằng đầu ra log thực tế, bảng so sánh, quy tắc vàng của rebase và quy trình làm việc nhóm an toàn.
Đọc bài viết →Phát triển phần mềmList comprehension trong Python: cú pháp, ví dụ và khi nào nên tránh
List comprehension trong Python: cú pháp, lọc dữ liệu, if-else, vòng lặp lồng nhau, thời gian đo thực tế và khi nào vòng lặp for thông thường tốt hơn.
Đọc bài viết →Cơ sở dữ liệu & SQLGiải thích SQL JOIN kèm ví dụ (Inner, Left, Right, Full)
Hiểu SQL JOIN từng bước với bảng và truy vấn mẫu: INNER, LEFT, RIGHT, FULL, CROSS và SELF, cùng lỗi thường gặp và mẹo hiệu năng.
Đọc bài viết →