Công cụ dành cho nhà phát triển · Bộ mã hóa và giải mã Base64
atob và btoa là viết tắt của từ gì và tại sao chúng chỉ hiểu tiếng Latin-1
· Lý lịch
base64 javascript unicode
atob và btoa có ngày từ Netscape và các tên này có nghĩa là 'ASCII thành nhị phân' và 'nhị phân thành ASCII'. Bài đăng này đề cập đến nguồn gốc của họ, cách các tiêu chuẩn WHATWG xác định họ và lý do tại sao họ chưa bao giờ học Unicode.
Tên hàm đọc giống như lỗi đánh máy — sự nhầm lẫn do tên gây ra và câu trả lời chỉ có một dòng
atob và btoa là các hàm dựng sẵn JavaScript được giới thiệu trong Netscape vào những năm 1990. Tên là chữ viết tắt: btoa là viết tắt của nhị phân thành ASCII và atob là viết tắt của ASCII thành nhị phân. Các tên phản ánh niên đại và thiết kế của chúng: chúng được tạo khi nhị phân có nghĩa là một chuỗi giá trị byte (0-255) thay vì Uint8Array hoặc Bộ đệm hiện đại hơn. Cách ghi nhớ thường được đưa ra cho các tên ít quan trọng hơn hợp đồng có thể quan sát được: một hàm ánh xạ chuỗi nhị phân tới Base64 và hàm kia đảo ngược chuỗi đó. Kho lưu trữ này không ghi lại quyết định đặt tên ban đầu, vì vậy bài viết tránh trình bày văn hóa dân gian dưới dạng lịch sử trình duyệt có nguồn gốc.
Các hàm yêu cầu một chuỗi nhị phân: đơn vị mã của mỗi ký tự phải nằm trong phạm vi 0-255, biểu thị một byte. Nếu bạn chuyển một ký tự có đơn vị mã ở trên 255 (như biểu tượng cảm xúc hoặc chữ cái có dấu từ bên ngoài tiếng Latin-1), thì hàm sẽ đưa ra InvalidCharacterError hoặc âm thầm tạo ra kết quả đầu ra không chính xác. btoa (nhị phân thành ASCII) mã hóa chuỗi nhị phân thành base64.
Những cái tên gợi ý điều gì và hợp đồng chuỗi byte thực sự chứng minh điều gì
Đầu vào phải là một chuỗi trong đó mỗi ký tự là một byte (đơn vị mã 0-255). btoa(hello) mã hóa các byte ASCII dưới dạng base64 và trả về aGVsbG8=. btoa với chữ cái e-cấp có vẻ hoạt động vì chữ cái e-cấp trong tiếng Latin-1 được tạo sẵn (U+00E9) có đơn vị mã là 233, nằm trong 0-255. Tuy nhiên, btoa mã hóa nó dưới dạng một byte đơn, 0xE9, chứ không phải UTF-8 byte 0xC3 0xA9 mà e-Acute sẽ tạo ra. Trước khi mảng được nhập trở thành vùng chứa byte thông thường, API JavaScript đã sử dụng các chuỗi có đơn vị mã đại diện cho byte. Mô hình đó vẫn hiển thị vì btoa từ chối các đơn vị mã ở trên 255. Niên đại chính xác của sản phẩm không được thiết lập bởi các tệp này; ranh giới lỗi được thiết lập bằng các thử nghiệm thực thi.
Sự tham nhũng thầm lặng này còn nguy hiểm hơn một lỗi: kết quả có vẻ ổn nhưng lại sai. atob (ASCII thành nhị phân) giải mã base64 trở lại chuỗi nhị phân. atob(aGVsbG8=) trả về lời chào. Đầu ra là một chuỗi nhị phân trong đó đơn vị mã của mỗi ký tự là 0-255, biểu thị một byte. Nếu bạn muốn chuyển đổi văn bản này thành văn bản Unicode thích hợp, bạn cần diễn giải các byte dưới dạng UTF-8 và giải mã chúng bằng TextDecoding.
Mô hình chuỗi nhị phân kế thừa - hành vi có thể quan sát được mà không cần xác nhận quyền sở hữu lịch sử trình duyệt chưa được xác minh
Đối với ASCII, bước bổ sung này là không cần thiết (ASCII là tập hợp con của UTF-8), nhưng đối với mọi byte không phải ASCII thì bước này là cần thiết. atob không thực hiện cách giải thích đó; nó trả về các byte thô dưới dạng chuỗi nhị phân.
Tiêu chuẩn WHATWG (tiêu chuẩn sống cho API web) xác định atob và btoa trong đặc tả HTML. Định nghĩa này bao gồm thuật toán giải mã tha thứ-base64 cho atob: nó bỏ qua khoảng trắng và chấp nhận phần đệm bị thiếu, làm cho base64 trong thế giới thực (bao gồm cả base64 được bọc MIME có ngắt dòng) có thể giải mã được. ToolAcre bình thường hóa khoảng trắng, URL-dấu câu an toàn và thiếu phần đệm trước khi gọi bộ giải mã trình duyệt. Sau đó, nó sao chép các đơn vị mã được trả về vào Uint8Array và áp dụng bộ giải mã UTF-8 nghiêm trọng. Sự kết hợp đó tách biệt cú pháp Base64 dễ tha thứ khỏi việc diễn giải văn bản nghiêm ngặt.
Hoạt động hiện tại trong quá trình triển khai này — bỏ qua việc chuẩn hóa bảng chữ cái và giải mã văn bản UTF-8 nghiêm ngặt
Chữ ký hàm không thay đổi, nhưng định nghĩa tiêu chuẩn là thẩm quyền cho chức năng của hàm. Tại sao atob và btoa chỉ chấp nhận tiếng Latin-1? Bởi vì khi chúng được thiết kế vào những năm 1990, JavaScript không có cách biểu diễn byte trực tiếp (không có Uint8Array hoặc ArrayBuffer). Cách duy nhất để truyền byte cho hàm là dùng chuỗi trong đó mỗi ký tự đại diện cho một byte.
Đây được gọi là chuỗi nhị phân và gây nhầm lẫn theo các tiêu chuẩn hiện đại. Chuỗi JavaScript là văn bản Unicode, không phải là chuỗi byte. Thiết kế đã kết hợp cả hai: một chuỗi trong đó mỗi đơn vị mã là 0-255 là một chuỗi nhị phân. Việc đặt tên phản ánh thời đại: ASCII trong btoa theo nghĩa đen có nghĩa là bảy bit cho văn bản ASCII nhưng việc triển khai chấp nhận bất kỳ byte nào (0-255). Việc thêm trực tiếp chế độ Unicode vào btoa sẽ thay đổi hợp đồng chuỗi byte lâu đời và rủi ro tương thích. Thay vào đó, nguồn được đánh giá sẽ soạn TextEncode trước khi mã hóa. Bài viết này có thể xác minh thành phần đó; nó bỏ qua các tuyên bố về động cơ của ủy ban tiêu chuẩn không được ghi lại trong kho.
Ví dụ hoạt động: truy tìm tha thứ-base64 trên một chuỗi có khoảng trắng và phần đệm bị thiếu - điều mà atob chấp nhận rằng bộ giải mã nghiêm ngặt sẽ từ chối
Các lựa chọn thay thế hiện đại tránh mô hình chuỗi nhị phân. Mã hóa API cung cấp TextEncode để chuyển đổi văn bản thành UTF-8 byte và TextDecoding để chuyển đổi UTF-8 byte trở lại văn bản.
Mã hóa và giải mã Base64 hiện được chỉ định trong thông số HTML cho cả chuỗi (atob và btoa) và mảng đã nhập. Công cụ mã hóa và giải mã Base64 sử dụng TextEncode và TextDecoding xung quanh atob và btoa, do đó bạn có thể mã hóa và giải mã văn bản Unicode một cách an toàn mà không gặp phải giới hạn Latin-1. Giá trị giãn cách hoặc không đệm thành công vì quá trình chuẩn hóa sẽ loại bỏ khoảng trắng và khôi phục độ dài khối được yêu cầu. Một giá trị có độ dài được làm sạch để lại phần dư 1 sẽ bị từ chối trước atob. Sự khác biệt này cho thấy "tha thứ" ở đây có nghĩa là gì: định dạng có thể phục hồi được chấp nhận, còn đầu vào không thể phục hồi về mặt cấu trúc thì không.
Các tiêu chuẩn mới hơn hoạt động trên Base64 cho các mảng đã nhập - được mô tả một cách định tính, kèm theo ghi chú để kiểm tra hỗ trợ trình duyệt hiện tại
Việc xử lý Unicode bằng btoa trước tiên yêu cầu mã hóa văn bản thành UTF-8 byte. Cách giải quyết cũ là btoa(unescape(encodeURIComponent(text))), tuy khó hiểu nhưng vẫn hoạt động: EncodeURIComponent mã hóa phần trăm UTF-8 byte, unescape chuyển đổi bộ ba trở lại thành ký tự và btoa mã hóa chuỗi nhị phân kết quả. Điều này hoạt động nhưng dựa vào các chức năng không được dùng nữa và khó đọc. Mã hiện đại nên sử dụng TextEncoding(text).map(byte => String.fromCharCode(byte)) theo sau là btoa hoặc tốt hơn là chuyển đổi trực tiếp sang Uint8Array và sử dụng Mã hóa API.
Atob không tự động gửi tin nhắn cho bạn; nó cung cấp cho bạn hệ nhị phân. atob(Y2Fmw6kg8J+YgA==) trả về một chuỗi nhị phân chứa các byte của văn bản được mã hóa UTF-8 với caf-accent và biểu tượng cảm xúc. Để khôi phục văn bản, hãy chuyển đổi chuỗi nhị phân thành Uint8Array và chuyển nó tới TextDecoding(utf-8). Công cụ mã hóa & giải mã Base64 thực hiện việc này một cách tự động: bạn dán văn bản, nó mã hóa thành UTF-8 byte, sau đó đến base64. API Base64 kiểu mảng đang phát triển trên các trình duyệt, nhưng nguồn này không sử dụng chúng. Tùy thuộc vào một yêu cầu kiểm tra khả năng tương thích hiện tại và kế hoạch dự phòng. Chuyển đổi mảng byte rõ ràng của ToolAcre vẫn có thể kiểm tra được và được bao phủ bởi bộ thử nghiệm hiện tại của nó.
Các lựa chọn thay thế kiểu mảng đang phát triển - hãy xác minh hỗ trợ trình duyệt hiện tại trước khi phụ thuộc vào chúng
Bạn dán base64, nó giải mã thành UTF-8 byte rồi chuyển thành văn bản. Bước chuỗi nhị phân trung gian bị ẩn vì đây là chi tiết triển khai của API những năm 1990. Hiểu atob và btoa rất hữu ích cho việc gỡ lỗi mã kế thừa hoặc làm việc với các API cũ cung cấp cho bạn chuỗi nhị phân. Hầu hết các mã mới nên tránh hoàn toàn mô hình chuỗi nhị phân.
Nếu bạn cần mã hóa hoặc giải mã base64, công cụ mã hóa & giải mã Base64 sẽ xử lý Unicode một cách chính xác. Nếu bạn đang xây dựng API, hãy chấp nhận Uint8Array hoặc chế độ xem mảng đã nhập hoặc ghi lại rõ ràng base64 của bạn là UTF-8 hay Latin-1. Khi xem xét mã sử dụng btoa với văn bản không phải ASCII mà không có TextEncode, đó là một lỗi: đầu ra mã hóa sai byte. Bộ đệm nút và thời gian chạy không phải trình duyệt xác định các API và quy tắc chấp nhận khác nhau. Họ bị loại trừ một cách có chủ ý. Các tuyên bố trong bài viết này liên quan đến các nguyên hàm của trình duyệt và trình bao bọc được triển khai trong apps/dev, chứ không phải mọi hàm có tên atob hoặc btoa trong mọi môi trường.
Bài học rút ra: hai hàm của những năm 1990 với hợp đồng chuỗi byte — cách bộ mã hóa và giải mã Base64 thực hiện UTF-8 bước xung quanh chúng sao cho có dấu, CJK và chuyến đi khứ hồi biểu tượng cảm xúc
Cái tên atob và btoa là những tạo tác đặc biệt của điện toán những năm 1990. Cách đặt tên hiện đại sẽ là base64Encode và base64Decode, đồng thời các API sẽ chấp nhận Uint8Array hoặc các chuỗi có khai báo mã hóa rõ ràng. Nhưng atob và btoa vẫn tồn tại trong trình duyệt để có khả năng tương thích ngược. Hiểu ý nghĩa của chúng (và những gì chúng không thể làm) giúp bạn tránh được lỗi ngầm khi mã hóa văn bản Unicode.
Công cụ mã hóa & giải mã Base64 thu hẹp khoảng cách: nó nói các ngôn ngữ UTF-8 và base64 mà mã hiện đại cần. Mẫu mạnh mẽ có tính cấu thành: mã hóa văn bản thành UTF-8 byte, chuyển đổi byte thành hợp đồng chuỗi nhị phân, sau đó gọi btoa; đảo ngược các bước xung quanh atob. Hãy thử một giọng, CJK ký tự và biểu tượng cảm xúc, sau đó yêu cầu văn bản được giải mã phải khớp với mọi điểm mã gốc.