Giới thiệu
Trong JavaScript, có thể sử dụng Base64 để mã hóa và giải mã chuỗi.
Trong bài viết này, bạn sẽ được giới thiệu các hàm JavaScript btoa và ____1010 có sẵn trong các trình duyệt web hiện đại.
Điều kiện tiên quyết
Để làm theo cùng với bài viết này, bạn sẽ cần:
- Một sự hiểu biết về các chuỗi trong JavaScript. Bạn có thể tham khảo cách làm việc với các chuỗi trong JavaScript để tìm hiểu thêm.
- Một sự hiểu biết về việc sử dụng các chức năng có sẵn cho
Output
SGVsbG8gV29ybGQh
Output
SGVsbG8gV29ybGQh
- Một sự hiểu biết về bảng điều khiển nhà phát triển. Bạn có thể tham khảo cách sử dụng bảng điều khiển nhà phát triển JavaScript để tìm hiểu thêm.
Mã hóa và giải mã chuỗi với base64
Output
SGVsbG8gV29ybGQh
Output
SGVsbG8gV29ybGQh
Output
SGVsbG8gV29ybGQh
Hãy nói rằng bạn có một chuỗi,
Output
SGVsbG8gV29ybGQh
Đầu ra của mã này là một chuỗi các ký tự với các chữ cái và số:
Output
SGVsbG8gV29ybGQh
Output
SGVsbG8gV29ybGQh
Hãy cùng lấy chuỗi được mã hóa từ trước đó,
Output
SGVsbG8gV29ybGQh
Đầu ra của mã này cho thấy chuỗi đã được chuyển đổi trở lại thông báo ban đầu của nó:
Output
Hello World!
Bây giờ, bạn có hai công cụ để mã hóa và giải mã base64.
Khám phá các trường hợp sử dụng phổ biến cho Base64
Bạn cũng có thể sử dụng Base64 để biểu diễn dữ liệu nhị phân theo cách tương thích với HTML, JavaScript và CSS. Ví dụ: bạn có thể nhúng hình ảnh nội tuyến trong tệp CSS hoặc JavaScript bằng Base64.
Có thể sử dụng Base64 để chuyển đổi đầu vào, như dữ liệu biểu mẫu hoặc JSON, thành một chuỗi có bộ ký tự giảm an toàn URL. Tuy nhiên, do cách các máy chủ nhất định có thể diễn giải các ký tự cộng với (
Output
SGVsbG8gV29ybGQh
Hiểu những hạn chế của Base64
Base64 không có nghĩa là một phương thức mã hóa an toàn.
Base64 cũng không phải là phương pháp nén. Mã hóa một chuỗi thành base64 thường dẫn đến sản lượng dài hơn 33%.
Sự kết luận
Trong bài viết này, bạn đã được giới thiệu cho btoa và
Output
SGVsbG8gV29ybGQh
Lưu ý: Tôi có thể sử dụng tài liệu vấn đề đã biết để xử lý UTF-8 và cung cấp một polyfill cho các trình duyệt cũ hơn. Can I Use documents the known issue for handling UTF-8 and provides a polyfill for older browsers.
Nếu bạn muốn tìm hiểu thêm về JavaScript, hãy xem trang chủ đề JavaScript của chúng tôi cho các bài tập và dự án lập trình.
Base64 là một nhóm các sơ đồ mã hóa nhị phân với văn bản tương tự đại diện cho dữ liệu nhị phân ở định dạng chuỗi ASCII bằng cách dịch nó thành biểu diễn Radix-64. Thuật ngữ base64 bắt nguồn từ một mã hóa chuyển nội dung MIME cụ thể. is a group of similar binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation. The term Base64 originates from a specific MIME
content transfer encoding. Các sơ đồ mã hóa Base64 thường được sử dụng khi cần phải mã hóa dữ liệu nhị phân cần được lưu trữ và chuyển qua phương tiện được thiết kế để đối phó với ASCII. Điều này là để đảm bảo rằng dữ liệu vẫn còn nguyên vẹn mà không cần sửa đổi trong quá trình vận chuyển. Base64 thường được sử dụng trong một số ứng dụng bao gồm email qua MIME và lưu trữ dữ liệu phức tạp trong XML. Một ứng dụng phổ biến của mã hóa Base64 trên web là mã hóa dữ liệu nhị phân để nó có thể được bao gồm trong một dữ liệu: URL. Trong JavaScript, có hai hàm tương ứng để giải mã và mã hóa chuỗi base64: Output
Output
SGVsbG8gV29ybGQh
Thuật toán được sử dụng bởi
Output
SGVsbG8gV29ybGQh
Output
SGVsbG8gV29ybGQh
Lưu ý rằng
Output
SGVsbG8gV29ybGQh
Output
SGVsbG8gV29ybGQh
Kích thước được mã hóa tăng
Mỗi chữ số Base64 đại diện cho chính xác 6 bit dữ liệu. Vì vậy, ba byte 8 bit của chuỗi đầu vào/tệp nhị phân (3 × 8 bit = 24 bit) có thể được biểu thị bằng bốn chữ số 6 bit 64 (4 × 6 = 24 bit).
Điều này có nghĩa là phiên bản Base64 của chuỗi hoặc tệp sẽ có kích thước ít nhất 133% so với nguồn của nó (tăng ~ 33%). Sự gia tăng có thể lớn hơn nếu dữ liệu được mã hóa nhỏ. Ví dụ: chuỗi
Output
Hello World!
Output
Hello World!
Output
Hello World!
Output
Hello World!
"Vấn đề Unicode"
Vì các chuỗi JavaScript là các chuỗi được mã hóa 16 bit, trong hầu hết các trình duyệt gọi
Output
Hello World!
Output
Hello World!
- Cái đầu tiên là thoát khỏi toàn bộ chuỗi và sau đó mã hóa nó;
- Cái thứ hai là chuyển đổi chuỗi UTF-16 thành một mảng các ký tự UTF-8 và sau đó mã hóa nó.
Dưới đây là hai phương pháp có thể.
Giải pháp số 1 - thoát khỏi chuỗi trước khi mã hóa nó
function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode"
Giải pháp này đã được đề xuất bởi Johan Sundström.
Một giải pháp khả thi khác mà không sử dụng các chức năng 'Unescape' và 'Escape' hiện nay không còn bị phản đối. Mặc dù vậy, sự thay thế này không thực hiện mã hóa base64 của chuỗi đầu vào. Lưu ý sự khác biệt trong đầu ra của
Output
Hello World!
Output
Hello World!
function b64EncodeUnicode(str) { return btoa(encodeURIComponent(str)); } function UnicodeDecodeB64(str) { return decodeURIComponent(atob(str)); } b64EncodeUnicode("✓ à la mode"); // "JUUyJTlDJTkzJTIwJUMzJUEwJTIwbGElMjBtb2Rl" UnicodeDecodeB64("JUUyJTlDJTkzJTIwJUMzJUEwJTIwbGElMjBtb2Rl"); // "✓ à la mode"
Giải pháp #2-Viết lại Output
SGVsbG8gV29ybGQh
4 và Output
SGVsbG8gV29ybGQh
3 bằng cách sử dụng function utf8_to_b64(str) {
return window.btoa(unescape(encodeURIComponent(str)));
}
function b64_to_utf8(str) {
return decodeURIComponent(escape(window.atob(str)));
}
// Usage:
utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU="
b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode"
0S và UTF-8
Output
SGVsbG8gV29ybGQhOutput
SGVsbG8gV29ybGQhLƯU Ý: Mã sau cũng hữu ích để lấy một arraybuffer từ chuỗi base64 và/hoặc ngược lại (xem bên dưới). The following code is also useful to get an ArrayBuffer from a Base64 string and/or vice versa (see below).
"use strict"; // Array of bytes to Base64 string decoding function b64ToUint6(nChr) { return nChr > 64 && nChr < 91 ? nChr - 65 : nChr > 96 && nChr < 123 ? nChr - 71 : nChr > 47 && nChr < 58 ? nChr + 4 : nChr === 43 ? 62 : nChr === 47 ? 63 : 0; } function base64DecToArr(sBase64, nBlocksSize) { const sB64Enc = sBase64.replace(/[^A-Za-z0-9+/]/g, ""); const nInLen = sB64Enc.length; const nOutLen = nBlocksSize ? Math.ceil(((nInLen * 3 + 1) >> 2) / nBlocksSize) * nBlocksSize : (nInLen * 3 + 1) >> 2; const taBytes = new Uint8Array(nOutLen); let nMod3; let nMod4; let nUint24 = 0; let nOutIdx = 0; for (let nInIdx = 0; nInIdx < nInLen; nInIdx++) { nMod4 = nInIdx & 3; nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << (6 * (3 - nMod4)); if (nMod4 === 3 || nInLen - nInIdx === 1) { nMod3 = 0; while (nMod3 < 3 && nOutIdx < nOutLen) { taBytes[nOutIdx] = (nUint24 >>> ((16 >>> nMod3) & 24)) & 255; nMod3++; nOutIdx++; } nUint24 = 0; } } return taBytes; } /* Base64 string to array encoding */ function uint6ToB64(nUint6) { return nUint6 < 26 ? nUint6 + 65 : nUint6 < 52 ? nUint6 + 71 : nUint6 < 62 ? nUint6 - 4 : nUint6 === 62 ? 43 : nUint6 === 63 ? 47 : 65; } function base64EncArr(aBytes) { let nMod3 = 2; let sB64Enc = ""; const nLen = aBytes.length; let nUint24 = 0; for (let nIdx = 0; nIdx < nLen; nIdx++) { nMod3 = nIdx % 3; if (nIdx > 0 && ((nIdx * 4) / 3) % 76 === 0) { sB64Enc += "\r\n"; } nUint24 |= aBytes[nIdx] << ((16 >>> nMod3) & 24); if (nMod3 === 2 || aBytes.length - nIdx === 1) { sB64Enc += String.fromCodePoint( uint6ToB64((nUint24 >>> 18) & 63), uint6ToB64((nUint24 >>> 12) & 63), uint6ToB64((nUint24 >>> 6) & 63), uint6ToB64(nUint24 & 63) ); nUint24 = 0; } } return ( sB64Enc.substr(0, sB64Enc.length - 2 + nMod3) + (nMod3 === 2 ? "" : nMod3 === 1 ? "=" : "==") ); } /* UTF-8 array to JS string and vice versa */ function UTF8ArrToStr(aBytes) { let sView = ""; let nPart; const nLen = aBytes.length; for (let nIdx = 0; nIdx < nLen; nIdx++) { nPart = aBytes[nIdx]; sView += String.fromCodePoint( nPart > 251 && nPart < 254 && nIdx + 5 < nLen /* six bytes */ ? /* (nPart - 252 << 30) may be not so safe in ECMAScript! So…: */ (nPart - 252) * 1073741824 + ((aBytes[++nIdx] - 128) << 24) + ((aBytes[++nIdx] - 128) << 18) + ((aBytes[++nIdx] - 128) << 12) + ((aBytes[++nIdx] - 128) << 6) + aBytes[++nIdx] - 128 : nPart > 247 && nPart < 252 && nIdx + 4 < nLen /* five bytes */ ? ((nPart - 248) << 24) + ((aBytes[++nIdx] - 128) << 18) + ((aBytes[++nIdx] - 128) << 12) + ((aBytes[++nIdx] - 128) << 6) + aBytes[++nIdx] - 128 : nPart > 239 && nPart < 248 && nIdx + 3 < nLen /* four bytes */ ? ((nPart - 240) << 18) + ((aBytes[++nIdx] - 128) << 12) + ((aBytes[++nIdx] - 128) << 6) + aBytes[++nIdx] - 128 : nPart > 223 && nPart < 240 && nIdx + 2 < nLen /* three bytes */ ? ((nPart - 224) << 12) + ((aBytes[++nIdx] - 128) << 6) + aBytes[++nIdx] - 128 : nPart > 191 && nPart < 224 && nIdx + 1 < nLen /* two bytes */ ? ((nPart - 192) << 6) + aBytes[++nIdx] - 128 : /* nPart < 127 ? */ /* one byte */ nPart ); } return sView; } function strToUTF8Arr(sDOMStr) { let aBytes; let nChr; const nStrLen = sDOMStr.length; let nArrLen = 0; /* mapping… */ for (let nMapIdx = 0; nMapIdx < nStrLen; nMapIdx++) { nChr = sDOMStr.codePointAt(nMapIdx); if (nChr > 65536) { nMapIdx++; } nArrLen += nChr < 0x80 ? 1 : nChr < 0x800 ? 2 : nChr < 0x10000 ? 3 : nChr < 0x200000 ? 4 : nChr < 0x4000000 ? 5 : 6; } aBytes = new Uint8Array(nArrLen); /* transcription… */ let nIdx = 0; let nChrIdx = 0; while (nIdx < nArrLen) { nChr = sDOMStr.codePointAt(nChrIdx); if (nChr < 128) { /* one byte */ aBytes[nIdx++] = nChr; } else if (nChr < 0x800) { /* two bytes */ aBytes[nIdx++] = 192 + (nChr >>> 6); aBytes[nIdx++] = 128 + (nChr & 63); } else if (nChr < 0x10000) { /* three bytes */ aBytes[nIdx++] = 224 + (nChr >>> 12); aBytes[nIdx++] = 128 + ((nChr >>> 6) & 63); aBytes[nIdx++] = 128 + (nChr & 63); } else if (nChr < 0x200000) { /* four bytes */ aBytes[nIdx++] = 240 + (nChr >>> 18); aBytes[nIdx++] = 128 + ((nChr >>> 12) & 63); aBytes[nIdx++] = 128 + ((nChr >>> 6) & 63); aBytes[nIdx++] = 128 + (nChr & 63); nChrIdx++; } else if (nChr < 0x4000000) { /* five bytes */ aBytes[nIdx++] = 248 + (nChr >>> 24); aBytes[nIdx++] = 128 + ((nChr >>> 18) & 63); aBytes[nIdx++] = 128 + ((nChr >>> 12) & 63); aBytes[nIdx++] = 128 + ((nChr >>> 6) & 63); aBytes[nIdx++] = 128 + (nChr & 63); nChrIdx++; } /* if (nChr <= 0x7fffffff) */ else { /* six bytes */ aBytes[nIdx++] = 252 + (nChr >>> 30); aBytes[nIdx++] = 128 + ((nChr >>> 24) & 63); aBytes[nIdx++] = 128 + ((nChr >>> 18) & 63); aBytes[nIdx++] = 128 + ((nChr >>> 12) & 63); aBytes[nIdx++] = 128 + ((nChr >>> 6) & 63); aBytes[nIdx++] = 128 + (nChr & 63); nChrIdx++; } nChrIdx++; } return aBytes; }
Xét nghiệm
/* Tests */ const sMyInput = "Base 64 \u2014 Mozilla Developer Network"; const aMyUTF8Input = strToUTF8Arr(sMyInput); const sMyBase64 = base64EncArr(aMyUTF8Input); alert(sMyBase64); const aMyUTF8Output = base64DecToArr(sMyBase64); const sMyOutput = UTF8ArrToStr(aMyUTF8Output); alert(sMyOutput);
Phụ lục: Giải mã chuỗi base64 thành Uint8array hoặc ArrayBuffer
Các chức năng này cho phép chúng tôi tạo ra Uint8arrays hoặc ArrayBuffers từ các chuỗi được mã hóa cơ sở64:
// "Base 64 \u2014 Mozilla Developer Network" const myArray = base64DecToArr( "QmFzZSA2NCDigJQgTW96aWxsYSBEZXZlbG9wZXIgTmV0d29yaw==" ); // "Base 64 \u2014 Mozilla Developer Network" const myBuffer = base64DecToArr( "QmFzZSA2NCDigJQgTW96aWxsYSBEZXZlbG9wZXIgTmV0d29yaw==" ).buffer; alert(myBuffer.byteLength);
Lưu ý: Hàm function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 1 trả về function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 2 của byte. Nếu mục tiêu của bạn là xây dựng bộ đệm dữ liệu thô 16 bit / 32 bit / 64 bit, hãy sử dụng đối số function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 3, đó là số byte mà thuộc tính function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 4 phải dẫn đến nhiều (function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 5 hoặc bị bỏ qua cho ASCII, Các chuỗi nhị phân (tức là, một chuỗi trong đó mỗi ký tự trong chuỗi được coi là một byte của dữ liệu nhị phân) hoặc các chuỗi được mã hóa UTF-8, function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 6 cho chuỗi UTF-16, function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 7 cho chuỗi UTF-32). The function function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 1 returns an function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 2 of bytes. If your aim is to build a buffer of 16-bit / 32-bit / 64-bit raw data, use the function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 3 argument, which is the number of bytes of which the function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 4 property must result a multiple (function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 5 or omitted for ASCII, binary strings (i.e., a string in which each character in the string is treated as a byte of binary data) or UTF-8-encoded strings, function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 6 for UTF-16 strings, function utf8_to_b64(str) { return window.btoa(unescape(encodeURIComponent(str))); } function b64_to_utf8(str) { return decodeURIComponent(escape(window.atob(str))); } // Usage: utf8_to_b64("✓ à la mode"); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8("4pyTIMOgIGxhIG1vZGU="); // "✓ à la mode" 7 for UTF-32 strings).