« Mã hóa » và « giải mã » một URL nghĩa là gì ?
Mã hóa một URL (« url encode », « urlencode ») biến mọi ký tự bị cấm trong một địa chỉ — khoảng trắng, ký tự có dấu, dấu amperand, dấu cộng — thành một dãy gồm dấu phần trăm theo sau là hai chữ số hexa của byte đó. Giải mã một URL (« url decode », « decoder url ») đọc các dãy đó theo chiều ngược: các byte được ghép lại rồi chuyển thành ký tự theo bảng mã được khai báo, thường là UTF-8. Đúng cặp từ khóa người ta tìm khi gõ « encoder decoder url » hay « percent encoding online ».
Percent-encoding không phải nén cũng không phải mã hóa: một từ có dấu sẽ dài gấp đôi, và ai cũng đọc được bằng mắt. Vai trò duy nhất của nó là cho mọi byte đi qua một URL, vốn theo mặc định chỉ nhận một tập con của ASCII. Ngược lại, Base64 dùng để vận chuyển byte qua kênh hoàn toàn dạng văn bản — hai thứ trông na ná nhưng không thay thế cho nhau.
Cách mã hóa URL bằng percent-encoding
Bước 1: văn bản được chuyển thành byte theo bảng mã đã chọn, mặc định là UTF-8. Bước 2: với mỗi byte, ta xem ký tự tương ứng có thuộc danh sách ký tự được phép của phạm vi đã chọn hay không. Bước 3: nếu có, nó được giữ nguyên; nếu không, nó trở thành %XX, với XX là hai chữ số hexa của byte. Bước 4: nếu tùy chọn thay khoảng trắng bằng + được bật, byte 32 sẽ bị thay bằng dấu cộng thay vì %20.
Ví dụ cụ thể: « café & été » trong phạm vi thành phần cho caf%C3%A9%20%26%20%C3%A9t%C3%A9. Hãy gõ đoạn văn bản này vào trình mã hóa: kết quả, kích thước đầu vào, kích thước đầu ra và phần phụ phí hiện ra trước khi bạn kịp nhả phím.
Bốn phạm vi mã hóa
Phạm vi thành phần chỉ giữ lại các chữ cái, chữ số và - _ . ! ~ * ' ( ) : đó là phạm vi của một giá trị tham số, và nó tương ứng với encodeURIComponent. Còn chuỗi truy vấn giữ thêm các dấu amperand và dấu bằng, để dựng lại một query string hoàn chỉnh. Còn đoạn đường dẫn cho phép / : @ & = + $ , ; để không phá vỡ các dấu gạch chéo. URL đầy đủ còn thêm ?, #, [ và ] : gần như không có gì bị escape, chỉ có khoảng trắng và các ký tự không phải ASCII mới biến thành %XX.
Cách giải mã một URL đã mã hóa
Việc giải mã quét chuỗi từ trái sang phải: một dấu phần trăm theo sau là hai chữ số hexa cho ra một byte, mọi ký tự khác được giữ nguyên sau khi chuyển đổi theo bảng mã đã chọn. Các byte sau đó được gộp lại và biến thành ký tự — hai byte cho « é », ba byte cho « 日 », bốn byte cho một emoji. Tab « Giải mã » hiển thị từng dãy tìm được, vị trí trong chuỗi, các byte và văn bản tương ứng.
Nếu dấu phần trăm không được theo sau bởi hai chữ số hợp lệ, lỗi sẽ rõ ràng: dãy chưa đủ hoặc ký tự hexa không hợp lệ. Nút « Sửa các % » biến các dấu phần trăm đứng riêng thành %25, làm cho chuỗi có thể giải mã mà không mất thông tin — cách an toàn nhất để xử lý một URL bị escape một phần.
Khoảng trắng: %20 hoặc + — quy tắc của biểu mẫu
%20 là khoảng trắng percent-encoding chặt chẽ: nó hoạt động ở đường dẫn, truy vấn, fragment và header. Còn dấu +, tuy vậy, chỉ là khoảng trắng trong định dạng application/x-www-form-urlencoded dùng bởi các biểu mẫu HTML và theo truyền thống bởi query string. Ở nơi khác nó vẫn là dấu cộng thật — và vì rất dễ nhầm, nên phải escape thành %2B ngay khi bạn mã hóa một giá trị.
Trong thực tế: để điền một ô biểu mẫu hay tái tạo hành vi của một <form>, chọn « Thay khoảng trắng bằng + ». Với URL chuyển hướng, canonical hay liên kết chia sẻ, hãy luôn ưu tiên %20. Còn trình giải mã thì coi + là khoảng trắng theo mặc định, và bạn có thể tắt hành vi này chỉ bằng một cú nhấp.
RFC 3986: unreserved, sub-delims và gen-delims
RFC 3986 chia các ký tự ASCII thành ba nhóm. Các ký tự không dành riêng — chữ cái, chữ số, - _ . ~ — luôn được giữ nguyên. Các sub-delim ! $ & ' ( ) * + , ; = và các gen-delim : / ? # [ ] @ mang ý nghĩa cấu trúc: chúng tách phần máy chủ, đường dẫn, truy vấn và fragment. Mọi thứ còn lại — khoảng trắng, dấu nháy, dấu góc nhọn, dấu ngoặc nhọn, dấu phần trăm — đều phải mã hóa.
Ba nhóm này chính là những gì tab « RFC 3986 & tham khảo » hiển thị từng ký tự: bấm vào một ô để xem mã hexa, nhóm của nó và những phạm vi giữ nguyên nó. Đây là tài liệu tham khảo nhanh nhất để trả lời câu hỏi « liệu tôi có phải escape ký tự này không ? ».
Ký tự có dấu, emoji và UTF-8
Một URL chỉ vận chuyển các byte ASCII an toàn, nên mọi ký tự vượt U+007F đều phải mã hóa. Trong UTF-8, « é » có giá trị C3 A9 và trở thành %C3%A9, « 日 » gồm ba byte và cho ra ba dãy, một emoji gồm bốn byte và tám ký tự đã mã hóa. Nếu kết quả có vẻ dài, đó không phải lỗi: đó là cái giá của việc tương thích với mọi giao thức. Cuối cùng, hãy lưu ý bảng mã gốc — giải mã bằng UTF-8 một chuỗi được mã hóa bằng Latin-1 sẽ cho ra ký tự rác, đó là lý do tab « Giải mã » đưa ra bốn tùy chọn.
Vì sao encodeURIComponent không phải lúc nào cũng đủ
encodeURIComponent mã hóa mọi thứ ngoại trừ A-Z a-z 0-9 - _ . ! ~ * ' ( ), điều này hợp với giá trị tham số nhưng làm hỏng một URL đầy đủ vì nó cũng escape dấu gạch chéo, dấu hai chấm và dấu amperand. encodeURI làm ngược lại: nó giữ cấu trúc của URL nhưng vẫn cho qua khoảng trắng và các ký tự có dấu, nên thất bại với văn bản thô. Cả hai cách đều được xử lý tại đây — và còn hơn thế, vì phạm vi « Chuỗi truy vấn » và phạm vi « Đoạn đường dẫn » đã thu hẹp khoảng cách giữa chúng.
Percent-encoding và Base64: hai công cụ khác nhau
Percent-encoding thay thế theo từng byte và giữ được tính đọc được của văn bản gốc, nhưng chuỗi dài ra đáng kể. Base64 gộp byte theo ba rồi viết lại bằng bảng 64 ký tự: gọn nhưng hoàn toàn không đọc được, và không dùng nguyên si trong URL nếu không có biến thể URL-safe. Tab « Chuyển đổi chéo » trình bày cả hai trong một cái nhìn, kèm thêm byte hexa, thực thể HTML và chuỗi JSON đã escape — để bạn chọn đúng cách biểu diễn trước khi sao chép bất cứ thứ gì.
Lỗi thường gặp: mã hóa hai lần và % đứng riêng
Lỗi phổ biến nhất là escape cùng một chuỗi hai lần: một khoảng trắng trở thành %20, rồi %2520, và máy chủ nhận nguyên vẹn « %20 ». Lỗi thứ hai là quên chính dấu phần trăm, vốn phải trở thành %25 — nếu không trình giải mã sẽ coi đó là đầu một dãy và báo lỗi hoặc cắt chuỗi. Cuối cùng, giữ một + không escape trong một tham số biểu mẫu chẳng khác nào chèn vào một khoảng trắng mà bạn không hề muốn. Trình giải mã báo các dãy sai định dạng, và nút « Sửa các % » sửa lỗi thứ hai mà không mất dữ liệu.
Những URL đã mã hóa ẩn ở đâu
Trong các query string theo dõi UTM, trong các redirect_uri và các giá trị trạng thái OAuth, trong các webhooks có URL đích chứa tham số lồng nhau, trong các URL callback được ký, trong nhật ký máy chủ, trong sitemap và canonical, trong các <a href> sinh ở phía client, trong các JWT có payload dạng Base64URL, trong các data: và các header Location, cũng như trong mọi biểu mẫu HTML gửi bằng GET. Biết mã hóa và giải mã trong một giây giúp bạn khỏi phải mở terminal chỉ vì một chuỗi.
Hiệu năng và thực hành tốt
Trong trình duyệt, việc mã hóa và giải mã chạy tuyến tính và không tốn kém gì đáng kể, kể cả với vài megabyte: mỗi ký tự chỉ được xử lý một lần, không đệ quy, không cấp phát theo từng ký tự. Hai cái bẫy duy nhất là mã hóa hai lần — hãy luôn kiểm tra round-trip trước khi lưu — và các URL dài vài kilobyte, thường bị proxy cắt khi vượt 2 000 ký tự. Hãy ghi rõ phạm vi dùng bên cạnh chuỗi kết quả: « thành phần » và « URL đầy đủ » không cho cùng kết quả trên cùng một văn bản.
Khuyến nghị cho
Lập trình viên back-end và front-end (query string, chuyển hướng, OAuth), người tích hợp và biên tập kỹ thuật (liên kết UTM, canonical, tracking), quản trị viên và DevOps (webhook, URL ký, nhật ký), tester và pentester (fuzzing tham số, vượt bộ lọc), sinh viên (hiểu UTF-8, ASCII và RFC 3986), cùng mọi người cần một trình mã hóa và giải mã URL trực tuyến nhanh, đầy đủ và bảo mật — với phần bổ sung là trình mã hóa giải mã Base64 và trình định dạng JSON.