Инструменты разработчика · Кодер и декодер Base64
Что означают atob и btoa и почему они понимают только латынь-1
· Фон
base64 javascript Юникод
atob и btoa датируются Netscape, а их имена означают «ASCII в двоичный файл» и «двоичный файл в ASCII». В этом посте рассказывается, откуда они взялись, как их определяют стандарты WHATWG и почему они никогда не изучали Unicode.
Имя функции читается как опечатка — путаница, которую вызывают имена, и однострочный ответ.
atob и btoa — это встроенные функции JavaScript, которые были представлены в Netscape в 1990-х годах. Имена представляют собой аббревиатуры: btoa означает «двоичный» для ASCII, а «atob» означает «ASCII» для «двоичного». Имена отражают их возраст и дизайн: они были созданы, когда двоичный код означал строку байтовых значений (0-255), а не более современные Uint8Array или Buffer. Мнемоника, часто присваиваемая именам, менее важна, чем наблюдаемый контракт: одна функция отображает двоичную строку в Base64, а другая меняет ее. Этот репозиторий не документирует первоначальное решение об именовании, поэтому статья избегает представления фольклора как истории браузера.
Функции ожидают двоичную строку: кодовая единица каждого символа должна находиться в диапазоне 0-255, что соответствует одному байту. Если вы передаете символ с кодовой единицей выше 255 (например, эмодзи или букву с акцентом из-за пределов латиницы — 1), функция выдает InvalidCharacterError или автоматически выдает неправильный вывод. btoa (двоичный код ASCII) кодирует двоичную строку в base64.
О чем говорят названия и что на самом деле доказывает контракт байтовой строки
Входные данные должны быть строкой, где каждый символ представляет собой байт (кодовая единица 0-255). btoa(hello) кодирует байты ASCII как base64 и возвращает aGVsbG8=. btoa с буквой e-acute, похоже, работает, поскольку заранее составленная латинская буква 1 e-acute (U+00E9) имеет кодовую единицу 233, которая находится в пределах 0-255. Однако btoa кодирует его как один байт 0xE9, а не UTF-8 байтов 0xC3 0xA9, которые должен создавать e-acute. До того, как типизированные массивы стали обычными байтовыми контейнерами, API JavaScript использовали строки, кодовые единицы которых обозначали байты. Эта модель остается видимой, поскольку btoa отклоняет блоки кода выше 255. Эти файлы не устанавливают точную хронологию продукта; граница отказа устанавливается с помощью выполняемых тестов.
Это скрытое повреждение более опасно, чем ошибка: результат выглядит нормально, но неверен. atob (ASCII в двоичный код) декодирует base64 обратно в двоичную строку. atob(aGVsbG8=) возвращает привет. Выходные данные представляют собой двоичную строку, в которой кодовая единица каждого символа равна 0-255, что соответствует одному байту. Если вы хотите преобразовать это в правильный текст Unicode, вам необходимо интерпретировать байты как UTF-8 и декодировать их с помощью TextDecoder.
Устаревшая модель двоичной строки — наблюдаемое поведение без непроверенного заявления об истории браузера.
Для ASCII этот дополнительный шаг не нужен (ASCII является подмножеством UTF-8), но для любых байтов, отличных от ASCII, он необходим. atob не делает такой интерпретации; он возвращает необработанные байты в виде двоичной строки.
Стандарты WHATWG (жизненные стандарты веб-API) определяют atob и btoa в спецификации HTML. Определение включает в себя алгоритм декодирования прощающего base64 для atob: он пропускает пробелы и принимает недостающие дополнения, что делает декодируемым реальный base64 (включая MIME-обернутый base64 с разрывами строк). ToolAcre нормализует пробелы, URL безопасную пунктуацию и недостающие поля перед вызовом декодера браузера. Затем он копирует возвращенные блоки кода в Uint8Array и применяет фатальный декодер UTF-8. Эта комбинация отделяет простой синтаксис Base64 от строгой интерпретации текста.
Текущее поведение в этой реализации — нормализация алфавита и строгое декодирование текста UTF-8.
Сигнатура функции не изменилась, но определение стандартов определяет, что делает функция. Почему atob и btoa принимают только Latin-1? Потому что, когда они были разработаны в 1990-х годах, у JavaScript не было способа напрямую представлять байты (нет Uint8Array или ArrayBuffer). Единственный способ передать байты в функцию — это строка, где каждый символ представляет один байт.
Это называется двоичной строкой и по современным стандартам сбивает с толку. Строка JavaScript представляет собой текст в формате Unicode, а не последовательность байтов. Дизайн объединил эти два понятия: строка, в которой каждая единица кода равна 0-255, является двоичной строкой. Именование отражает эпоху: ASCII в btoa буквально означало семь битов для текста ASCII, но реализация принимает любой байт (0-255). Добавление режима Unicode непосредственно в btoa изменило бы его давний контракт байтовых строк и повысило бы риск совместимости. Вместо этого проверенный источник составляет TextEncoder перед кодированием. Эта статья может подтвердить этот состав; в нем отсутствуют утверждения о мотивах комитета по стандартам, не записанные в репозитории.
Рабочий пример: трассировка forgiving-base64 для строки с пробелами и отсутствующими дополнениями — что atob принимает, а строгий декодер отвергает
Современные альтернативы избегают модели двоичной строки. Кодировка API предоставляет TextEncoder для преобразования текста в UTF-8 байтов и TextDecoder для преобразования UTF-8 байтов обратно в текст.
Кодирование и декодирование Base64 теперь указано в спецификации HTML как для строк (atob и btoa), так и для типизированных массивов. Инструмент кодирования и декодера Base64 использует TextEncoder и TextDecoder на основе atob и btoa, поэтому вы можете безопасно кодировать и декодировать текст Unicode без ограничений Latin-1. Значение с пробелами или без дополнений считается успешным, поскольку нормализация удаляет пробелы и восстанавливает требуемую длину блока. Значение, очищенная длина которого оставляет остаток единица, отклоняется до atob. Это различие показывает, что здесь означает «прощающий»: восстанавливаемое форматирование принимается, а структурно невозможный ввод — нет.
Новые стандарты работают на Base64 для типизированных массивов — качественное описание с примечанием о проверке текущей поддержки браузера.
Для обработки Unicode с помощью btoa необходимо сначала закодировать текст в UTF-8 байт. Старым обходным решением был btoa(unescape(encodeURIComponent(text))), который сбивает с толку, но работает: encodeURIComponent процентно кодирует UTF-8 байт, unescape преобразует триплеты обратно в символы, а btoa кодирует полученную двоичную строку. Это работает, но основано на устаревших функциях и его трудно читать. Современный код должен использовать TextEncoder(text).map(byte => String.fromCharCode(byte)) с последующим btoa или, что лучше, напрямую преобразовать в Uint8Array и использовать кодировку API.
Атоб не отправляет вам текст автоматически; он дает вам двоичный код. atob(Y2Fmw6kg8J+YgA==) возвращает двоичную строку, содержащую байты текста в кодировке UTF-8 с caf-accent и эмодзи. Чтобы восстановить текст, преобразуйте двоичную строку в Uint8Array и передайте ее в TextDecoder(utf-8). Инструмент кодирования и декодера Base64 делает это автоматически: вы вставляете текст, он кодирует его в UTF-8 байт, а затем в base64. API-интерфейсы Base64 для типизированных массивов развиваются во всех браузерах, но в этом источнике они не используются. В зависимости от одного требуется текущая проверка совместимости и запасной план. Явное преобразование байтового массива ToolAcre остается поддающимся проверке и покрывается текущим набором тестов.
Альтернативы типизированным массивам развиваются — проверьте текущую поддержку браузера, прежде чем полагаться на них.
Вы вставляете base64, он декодирует в UTF-8 байт, а затем в текст. Промежуточный этап обработки двоичной строки скрыт, поскольку это деталь реализации API 1990-х годов. Понимание atob и btoa полезно для отладки устаревшего кода или работы со старыми API, которые передают вам двоичные строки. В большинстве новых кодов следует полностью избегать модели двоичной строки.
Если вам нужно кодировать или декодировать Base64, инструмент кодирования и декодера Base64 правильно обрабатывает Unicode. Если вы создаете API, примите Uint8Array или представление типизированного массива или четко задокументируйте, является ли ваш base64 UTF-8 или Latin-1. При просмотре кода, который использует btoa с текстом, отличным от ASCII, без TextEncoder, это ошибка: выходные данные кодируют неправильные байты. Node Buffer и небраузерные среды выполнения определяют разные API и правила принятия. Они намеренно исключены. Претензии в этой статье касаются примитивов браузера и оболочки, реализованных в apps/dev,, а не каждой функции с именем atob или btoa в каждой среде.
Вывод: две функции 1990-х годов с контрактом байтовой строки — как кодировщик и декодер Base64 выполняют UTF-8 вокруг них, так что акценты, CJK и эмодзи туда и обратно
Имена atob и btoa — своеобразные артефакты вычислительной техники 1990-х годов. Современные имена будут base64Encode и base64Decode, а API-интерфейсы будут принимать Uint8Array или строки с явными объявлениями кодировки. Но atob и btoa сохраняются в браузерах для обеспечения обратной совместимости. Понимание того, что они означают (и чего они не могут сделать), поможет вам избежать скрытого повреждения при кодировании текста в Юникоде.
Инструмент кодирования и декодера Base64 устраняет этот пробел: он поддерживает языки UTF-8 и base64, необходимые современному коду. Надежный шаблон является композиционным: кодируйте текст в UTF-8 байт, преобразуйте байты в контракт двоичной строки, затем вызывайте btoa; отмените эти шаги вокруг atob. Попробуйте использовать акцент, CJK символов и эмодзи, а затем потребовать, чтобы декодированный текст соответствовал каждой исходной кодовой точке.