Передовые знания кодирования Base64, исчерпанные в одной статье, исследуйте происхождение и ищите правду.

внешний интерфейс JavaScript
Передовые знания кодирования Base64, исчерпанные в одной статье, исследуйте происхождение и ищите правду.

предисловие

Эта статья включена вПродвинутые основы интерфейсаКолонка, добро пожаловать, чтобы следовать и собирать, прошлые классики:

Коллекция не ЗВЕЗДА является изгоем! какие

контур

Удобно читать на мобильном:

  • Применение Base64 во внешнем интерфейсе
  • Источник кодирования данных Base64
  • Значение кодировки Base64 64
  • Преимущества и недостатки кодировки Base64
  • Некоторые компьютерные и интерфейсные основы
  • ASCII, Юникод, UTF-8
  • Кодирование и декодирование Base64
  • Другие зрелые решения
  • напиши в конце

Применение Base64 во внешнем интерфейсе

Кодировка Base64, вы должны знать, давайте взглянем на некоторые из ее распространенных приложений во внешнем интерфейсе:
Конечно, большинство сцен основано наData URLs

Создание изображения холста

холстtoDataURLВы можете преобразовать содержимое холста холста в формат кодировки base64, включая отображение изображения.data URI.

const ctx = canvasEl.getContext("2d");
// ...... other code
const dataUrl = canvasEl.toDataURL();

// data:image/png;base64,iVBORw0KGgoAAAANSUhE.........

Я думаю, вы рисуете, к вам присоединяются новые пользователи, чтобы получить самый последний интерфейс рисования, вы также можете передавать сообщения в формате Base64.

файл прочитан

FialeReaderreadAsDataURLЗагруженный файл можно преобразовать в URI данных в формате base 64. Более распространенным сценарием является вырезание и загрузка пользовательских аватаров.

function readAsDataURL() {
    const fileEl = document.getElementById("inputFile");
    return new Promise((resolve, reject) => {
        const fd = new FileReader();
        fd.readAsDataURL(fileEl.files[0]);
        fd.onload = function () {
            resolve(fd.result);
            // data:image/png;base64,iVBORw0KGgoAAAA.......
        }
        fd.onerror = reject;
    });
}

jwt

jwt состоит из трех частей: заголовка, полезной нагрузки и подписи.После декодирования первых двух их можно увидеть в виде открытого текста. братьСильнейший JWT на национальном сервере генерирует Токен для проверки входа, после прочтения которого вы гарантированно научитесь!Токен внутри проверен.

image.png

Изображения веб-сайтов и небольшие изображения

Оптимизация иконок мобильного сайта

<link rel="icon" href="data:," />
<link rel="icon" href="data:;base64,=" />

Что касается того, как получить это значениеdata:,из:

<canvas height="0" width="0" id="canvas"></canvas>
<script>
    const canvasEl = document.getElementById("canvas");
    const ctx = canvasEl.getContext("2d");
    dataUrl = canvasEl.toDataURL();
    console.log(dataUrl);  // data:,
</script>

маленькая картинка

У этого есть много сцен, таких как теги img, фоновые изображения и т. д.

тег img:

<img src="data:image/png;base64,iVBORw0KGgoAAAA......." />

css фоновое изображение:

.bg{
    background: url(data:image/png;base64,iVBORw0KGgoAAAA.......)
}

Простое шифрование данных

Конечно, это не очень хороший способ, но, по крайней мере, он затрудняет вам интерпретацию.


  const username = document.getElementById("username").vlaue; 
  const password = document.getElementById("password").vlaue;  
  const secureKey = "%%S%$%DS)_sdsdj_66";
  const sPass = utf8_to_base64(password + secureKey);
  
  doLogin({
      username,
      password: sPass
  })
  

SourceMap

Позаимствуйте кусок кода у Ruan Dashen, обратите внимание на поле Mappings, которое на самом деле является содержимым формата кодировки bas64.Конечно, если вы попытаетесь решить его напрямую, это не удастся.

{
    version : 3,
    file: "out.js",
    sourceRoot : "",
    sources: ["foo.js", "bar.js"],
    names: ["src", "maps", "are", "fun"],
    mappings: "AAgBC,SAAQ,CAAEA"
  }

Для конкретной реализации, пожалуйста, смотрите официальныйbase64-vlq.jsдокумент.

Обфусцированный зашифрованный код

Известная библиотека обфускации кода,javascript-obfuscator, который также имеет несколько кодов base64, давайте взглянем на варианты:
webpack-obfuscatorТакже на основе его упаковки.

    --string-array-indexes-type '<list>' (comma separated) [hexadecimal-number, hexadecimal-numeric-string]
    --string-array-encoding '<list>' (comma separated) [none, base64, rc4]
    --string-array-index-shift <boolean>
    --string-array-wrappers-count <number>
    --string-array-wrappers-chained-calls <boolean>

image.png

разное

Сертификаты открытого ключа X.509, ключи SSH github, файлы mht, вложения электронной почты и т. д. — все они имеют тень Base64.

Источник кодировки данных Base64

Ранние протоколы передачи почты основывались на тексте ASCII и плохо работали с двоичными файлами, такими как изображения и видео. ASCII в основном используется для отображениясовременный английский, пока только определил128символов, включая управляющие символы и отображаемые символы. Чтобы решить вышеуказанные проблемы, родилась кодировка Base64.

Base64 — это кодек, основная функция которого заключается не в обеспечении безопасности, а в обеспечении безошибочной передачи контента между различными шлюзами, это основная функция кодирования Base64.

Помимо кодировки данных Base64, на самом делеКодировка данных Base32, кодировка данных Base16, видетьRFC 4648.

Значение кодировки Base64 64

64 означает 64 символа.

Сравнительная таблица Base64, заимствованнаяПринцип Base64Картина:
image.png

  1. A-Z 26
  2. a-z 26
  3. 0-9 10
  4. + / 2

26 + 26 + 10 + 2 = 64

Конечно есть еще один персонаж=, который является заполняющим символом, о котором будет сказано позже, не относится к категории 64.

сравнительной таблицызначение индекса, Обратите внимание, что кодирование и декодирование base64 будут использоваться позже.

Преимущества и недостатки кодировки Base64

преимущество

  1. Может преобразовывать двоичные данные (например, изображения) в печатные символы для облегчения передачи данных.
  2. Простое шифрование данных, безопасное для невооруженного глаза
  3. Если вы обрабатываете изображения в html или css, вы можете уменьшить количество http-запросов.

недостаток

  1. После кодирования контента объем становится больше, минимум на 1/3
    Поскольку три байта становятся четырьмя байтами, когда есть только один байт, он станет как минимум три байта.
  2. Кодирование и декодирование требуют дополнительной работы

Поговорив о преимуществах и недостатках, вернемся к теме:

Сегодня мы сосредоточимся на преобразовании кодировки uf8 в кодировку Base64:

Основной процесс

char => кодовая точка => кодировка utf-8 => кодировка base64

Прежде чем нам нужно понять знание кодирования, чтобы понять знание кодирования, мы должны сначала понять некоторые базовые знания о компьютерах.

Некоторые основы работы с компьютером и внешним интерфейсом

биты и байты

бит ака бит. В компьютерном мире представление информации — это только 0 и 1, которые могут представлять два состояния.
Один бит двоичного кода может представлять два состояния, а N битов могут представлять2^Nсостояние.

байт(Byte)имеет 8 бит(Bit) image.png

Таким образом, байт может представлять2^8= 256 состояний;

Получить кодовую точку Unicode символа

String.prototype.charCodeAtМожно получить кодовую точку символа, а диапазон0 ~ 65535. Обратите внимание на это место, оно связано с количеством байтов utf-8 позади.

"a".charCodeAt(0)  // 97
"中".charCodeAt(0) // 20013

базовое представление

  1. 0bв начале может представлять двоичный

Уведомление0b10000000= 128 ,0b11000000=92, который будет использоваться позже.

0b11111111 // 255
0b10000000 // 128 后面会用到
0b11000000 // 192 后面会用到

image.png

  1. 0xВначале он может представлять шестнадцатеричный
0x11111111 // 286331153

image.png

0oНачало может быть выражено восьмеричным, так что больше говорить не буду, оно не будет задействовано в первую очередь.

базовое преобразование

Десятичная система с другими основаниями
Number.prototype.toString(radix)Вы можете конвертировать десятичные числа в другие базы.

100..toString(2)  // 1100100
100..toString(16) // 64, 也等于 ox64

Преобразование других оснований в десятичные
parseInt(string, radix)Вы можете преобразовать другие основания в десятичные.

parseInt("10000000", 2) // 128
parseInt("10",16) // 16

Вот дополнительное упоминание символа унарного оператора+Вы можете преобразовать строки в числа, которые будут использоваться позже, как упоминалось ранее.0b,0o,0xЭто будет работать здесь.

+"1000" // 1000
+"0b10000000" // 128
+"0o10" // 8
+"0x10" // 16

операция вытеснения

В этой статье рассматриваются толькопереместить вправоОперация, просто сдвиг вправо, сдвиг вправо эквивалентна делению на 2, если это целое число,Проще говоря, иди вниз, переместите несколько цифр, чтобы удалить несколько цифр, что на самом деле то же самое, что деление на 10 в десятичном виде.

64 >> 2 = 16Давайте посмотрим на процесс

0 1 0 0 0 0 0 0       64
-------------------
   0 1 0 0 0 0 | 0 0  16

Один юань&операции и унарные|действовать

Один юань&

Когда оба равны 1, значение равно 1.Роль этой статьи можно использовать, чтобы подняться выше, подробности см. в коде.
3553 & 36 = 0b110111100001 & 0b111111 = 100001
Поскольку старшие биты отсутствуют, они не могут быть все равны 1, поэтому все они равны 0, иНизкий эквивалент, чтобы скопировать его снова.

110111 100001
       111111
------------
000000 100001

один доллар |
Когда любой из них равен 1, выход равен 1.Этот лист используется для заполнения0. Например, дополнение 3 к 8-битному двоичному коду
3 | 256 = 11 | 100000000 = 100000011

100000011.substring(1)Это то же самое, что и 8-битный двоичный код?00000011

Обладая этими базовыми знаниями, мы начинаем понимать знания, связанные с кодированием.

ASCII, Юникод, UTF-8

ASCII-код

Первая цифра кода ASCII всегда равна 0, тогда фактическое состояние, которое может быть представлено, равно2^7= 128 состояний.

ASCII в основном используется для отображениясовременный английский, пока только определил128Символ, содержащий управляющие символы и отображаемые символы.

  • от 0 до 31ASCII-кодЧасто используется для управления периферийными устройствами, такими как принтеры.
  • от 32 до 127ASCII-кодозначаемый,Можно найти на нашей клавиатуре

Полную таблицу соответствия кодов ASCII см.Базовый ASCII и расширенный ASCII

Далее идет кодировка Unicode и UTF-8, сначала запомните это важное знание:

  • Unicode: набор символов
  • UTF-8: правила кодирования

Unicode

Unicode присваивает уникальный номер всем символам в мире (кодовая точка), этот номер находится в диапазоне от 0x000000 до 0x10FFFF (шестнадцатеричный), их более 1 миллиона, каждый символ имеет уникальный номер Unicode, этот номер обычно записывается в шестнадцатеричном формате, а U+ добавляется впереди. Например:Юникод U+6398.

  • от U+0000 до U+FFFF

Первые 65536 битов символов, диапазон кодовых точек от 0 до216-1. Здесь размещены все самые распространенные символы.

  • от U+010000 до U+10FFFF

Здесь размещаются остальные символы с кодовыми точками от U+010000 до U+10FFFF.

В Unicode есть понятие плоскости, поэтому здесь оно не будет раскрываться.

Unicode указывает только кодовую точку для каждого символа, какой порядок байтов используется для представления этой кодовой точки, это связано с методом кодирования.

UTF-8

UTF-8 — наиболее часто используемая реализация Unicode в Интернете. Существуют также такие реализации, как UTF-16 (символы представлены двумя или четырьмя байтами) и UTF-32 (символы представлены четырьмя байтами).

UTF-8 — это метод кодирования переменной длины, количество используемых байтов — отот 1 до 4, последний должен быть больше 4. Этот диапазон от 1 до 4 является ключом к последующему кодированию и декодированию.

Правила кодировки UTF-8:

  1. Для символов только с одним байтом первый бит байта устанавливается равным0, последние 7 цифр — это Unicode-код этого символа. В это время даДля английских букв кодировка UTF-8 и код ASCII совпадают.
  2. дляnбайтовый символ (n > 1), перед первым байтомnбиты установлены на1, первыйn + 1набор бит0, первые две цифры следующих байтов всегда устанавливаются равными10. Остальные неупомянутые двоичные биты — это все коды Unicode этого символа, как показано в следующей таблице:
Диапазон кодовых точек Unicode (шестнадцатеричный) Десятичный диапазон Кодировка UTF-8 (двоичная) количество байтов
0000 0000 ~ 0000 007F 0 ~ 127 0xxxxxxx 1
0000 0080 ~ 0000 07FF 128 ~ 2047 110xxxxx 10xxxxxx 2
0000 0800 ~ 0000 FFFF 2048 ~ 65535 1110xxxx 10xxxxxx 10xxxxxx 3
0001 0000 ~ 0010 FFFF 65536 ~ 1114111 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 4

Возможно, мы не видели количество байтов2или для4характер, байты2можешь идтиТаблица соответствий UnicodeНайти здесь и равно4ты можешь пойти сюдаUnicode® 13.0 Versioned Charts Index

Следующие кодовые точки находятся в0000 0080 ~ 0000 07FF, кодировка utf-8 требует 2 байтаimage.png

Следующие кодовые точки находятся в0001 0000 ~ 0010 FFFF, кодировка utf-8 требует 4 байтаimage.png

Может быть, это сложно понять, просто говоря об этом здесь, мы используем английские символы соответственно.aи китайские иероглистыОбъяснить:

Чтобы проверить результаты, вы можете перейти кConvert UTF8 to Binary Bits - Online UTF8 Tools

английские символыa

  1. Сначала получите его кодовую точку,"a".charCodeAt(0)равный97
  2. Сравнительная таблица, 0~127, обязательна1байты
  3. 97..toString(2)получить кодировку1100001
  4. Согласно формату0xxxxxxxзаливка, конечный результат
01100001

Китайские символы

  1. Сначала получите его кодовую точку,"掘".charCodeAt(0)равный25496
  2. Справочная форма, 2048 ~ 65535 обязательна3байты
  3. 25496..toString(2)закодироваться110 001110 011000
  4. Корневой формат1110xxxx 10xxxxxx 10xxxxxxЗаполните, окончательный результат выглядит следующим образом
11100110 10001110 10011000

Convert UTF8 to Binary Bits - Online UTF8 ToolsРезультат выполнения: точное совпадение

image.png

Абстрактный метод преобразования символов в двоичный формат utf8

Основываясь на приведенной выше таблице и процессе преобразования, мы абстрагируем метод, который находится вПосле этого кодирование и декодирование Base64 имеет решающее значение.:

Сначала посмотрите на функцию, охватывающую диапазон 1-3 байта кодировки utf8.

console.log(to_binary("A"))  // 11100001
console.log(to_binary("س"))  // 1101100010110011
console.log(to_binary("掘")) // 111001101000111010011000

Методы, как показано ниже

function to_binary(str) {
  const string = str.replace(/\r\n/g, "\n");
  let result = "";
  let code;
  for (var n = 0; n < string.length; n++) {
    //获取麻点
    code = str.charCodeAt(n);
    if (code < 0x007F) { // 1个字节
      // 0000 0000 ~ 0000 007F  0 ~ 127 1个字节
      
      // (code | 0b100000000).toString(2).slice(1)
      result += (code).toString(2).padStart(8, '0'); 
    } else if ((code > 0x0080) && (code < 0x07FF)) {
      // 0000 0080 ~ 0000 07FF	128 ~ 2047 2个字节
      // 0x0080 的二进制为 10000000 ,8位,所以大于0x0080的,至少有8位
      // 格式 110xxxxx 10xxxxxx     

      // 高位 110xxxxx
      result += ((code >> 6) | 0b11000000).toString(2);
      // 低位 10xxxxxx
      result += ((code & 0b111111) | 0b10000000).toString(2);
    } else if (code > 0x0800 && code < 0xFFFF) {
      // 0000 0800 ~ 0000 FFFF	2048 ~ 65535	3个字节
      // 0x0800的二进制为 1000 00000000,12位,所以大于0x0800的,至少有12位
      // 格式 1110xxxx 10xxxxxx 10xxxxxx

      // 最高位 1110xxxx
      result += ((code >> 12) | 0b11100000).toString(2);  
      // 第二位 10xxxxxx
      result += (((code >> 6) & 0b111111) | 0b10000000).toString(2);
      // 第三位 10xxxxxx
      result += ((code & 0b111111) | 0b10000000).toString(2);
    } else {
      // 0001 0000 ~ 0010 FFFF   65536 ~ 1114111   4个字节 
      // https://www.unicode.org/charts/PDF/Unicode-13.0/U130-2F800.pdf
      throw new TypeError("暂不支持码点大于65535的字符")
    }
  }
  return result;
}

В методе есть три места, которые немного сложно понять, давайте интерпретируем их вместе:

  1. двухбайтовый(code >> 6) | 0b11000000

Его роль заключается в генерации двоичного кода высокого порядка.
Мы объясняем с настоящим каштаном, сسНапример, его кодовая точка0x633,существует0000 0080 ~ 0000 07FFмежду , занимая два байта, а его двоичный код11 000110011, формат заполнения следующий, следует использовать младший разряд6 бит.

110xxxxx 10xxxxxx

Для удобства наблюдения положим11 000110011приспособиться11000 110011.

(код >> 6) равен 00110011 >> 6, сдвиг вправо на 6 бит и прямое уничтожение младших 6 бит. Почему 6, потому что для младшего разряда требуется 6 бит.После перемещения 6 бит вправо, остальные биты используются для операции старшего разряда.

11000000
   11000 | 110011 
--------------
11011000      
  1. двухбайтовый(code & 0b111111) | 0b10000000
    Роль, используемая для генерации младшего двоичного файла. кسНапример,11000 110011, формат заполнения
  110xxxxx 10xxxxxx

(code & 0b111111)这步的操作是为了干掉6位以上的高位,仅仅保留低6位. Один юань&Символ, когда обе стороны равны 1, будет 1, замечательно.

11000 110011
      111111
------------------
      110011  

затем продолжайте| 0b10000000, в основном в соответствии с форматом10xxxxxxЗаполнение выполняется, чтобы заполнить его 8 битами.

 11000 110011
       111111         (code & 0b111111)
 ------------------
       110011  
    10 000000         (code & 0b111111) | 0b10000000
-------------------
    10 110011

Кодирование и декодирование Base64

правила кодирования utf-8 в Base64

  1. Получить код Unicode для каждого символа, перейти на кодировку UTF-8
  2. три байтаВ группе всего 24 двоичных бита
    Количество байтов не делится на 3, дополненное в конце 0-байтовым значением
  3. согласно с6 битГруппа групп, первые два бита заполнены 0, а 8 бит собраны
  4. Рассчитать стоимость каждого пакета
  5. с первым4Значение шага используется в качестве индекса, и перейдите к таблице кодов ASCII, чтобы найти соответствующее значение.
  6. заменить первый2шагДобавьте количество байтовиз=
    например первый2Добавил 2 байта, за ним 2=

слишком большой掘AНапример, мы передаем вышеutf8_to_binaryспособ получить кодировку utf8
11100110 10001110 10011000 11000001, количество байт не делится на 3 и заполняется позже

11100110
10001110
10011000
01000001
--------
00000000
00000000

6-битная группа делится на четыре группы, старшее дополнение0, использовать|Разделить и заполнить.

00 | 111001  => 57 => 5
00 | 101000  => 40 => o
00 | 111010  => 58 => 6
00 | 011000  => 24 => Y

00 | 110000  => 16 => Q
00 | 010000  => 16 => Q
00 | 000000  =>    => =
00 | 000000  =>    => =

оказаться:5o6YQQ==, Идеально.

Реализация кода правила кодирования utf-8 в Base64

На основании вышеизложенногоto_binaryМетод и правила преобразования base64 очень просты:
Давайте посмотрим на эффект реализации, очень хороший, иbase64.usРезультаты точно такие же.

console.log(utf8_to_base64("a")); // YQ==

console.log(utf8_to_base64("Ȃ"));  // yII=

console.log(utf8_to_base64("中国人")); // 5Lit5Zu95Lq6

console.log(utf8_to_base64("Coding Writing 好文召集令|后端、大前端双赛道投稿,2万元奖池等你挑战!"));
//Q29kaW5nIFdyaXRpbmcg5aW95paH5Y+s6ZuG5Luk772c5ZCO56uv44CB5aSn5YmN56uv5Y+M6LWb6YGT5oqV56i/77yMMuS4h+WFg+WlluaxoOetieS9oOaMkeaImO+8gQ==

Полный код выглядит следующим образом:


const BASE64_CHARTS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
function utf8_to_base64(str: string) {
  let binaryStr = to_binary(str);
  const len = binaryStr.length;

  // 需要填补的=的数量
  let paddingCharLen = len % 24 !== 0 ? (24 - len % 24) / 8 : 0;

  //6个一组
  const groups = [];
  for (let i = 0; i < binaryStr.length; i += 6) {
    let g = binaryStr.slice(i, i + 6);
    if (g.length < 6) {
      g = g.padEnd(6, "0");
    }
    groups.push(g);
  }

  // 求值
  let base64Str = groups.reduce((b64str, cur) => {
    b64str += BASE64_CHARTS[+`0b${cur}`]
    return b64str
  }, "");

  // 填充=
  if (paddingCharLen > 0) {
    base64Str += paddingCharLen > 1 ? "==" : "=";
  }

  return base64Str;
}

Что же касается расшифровки, то это обратный процесс, и я предоставляю каждому понять его.

Другие зрелые решения

  1. Конечно, на основе существующихbtoaа такжеatob,

Но unescape - устаревший метод

function utf8_to_b64( str ) {
  return window.btoa(unescape(encodeURIComponent( str )));
}

function b64_to_utf8( str ) {
  return decodeURIComponent(escape(window.atob( str )));
}

// Применение: utf8_to_b64('✓ в режиме'); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8('4pyTIMOgIGxhIG1vZGU='); // "✓ в режиме"

  1. MDNrewriting atob() and btoa() using TypedArrays and UTF-8

Он поддерживает до 6 байт, но читабельность не очень хорошая.

  1. сторонняя библиотекаbase64-jsа такжеjs-base64Все они представляют собой библиотеки с более чем миллионом загрузок в неделю.

Хотя существует так много зрелых, мы можем лучше понять принцип кодирования Base64, если поймем и реализуем его сами.

добавить немного больше

  1. схема кодирования

занимать[Вы действительно знаете Unicode и UTF-8?] Картинка:

image.png

  1. DOMStringдаutf-16кодирование

напиши в конце

Писать нелегко, ваши три подряд (один лайк, один комментарий, один лайк) — моя самая большая мотивация.

подобноболее ста, а затем писать статьи о программировании, таком как браузеры, DOM, JS и т. д.

Цитировать

Version-Specific Charts
Unicode13.0.0
Unicode® 13.0 Versioned Charts Index
RFC 4648 | The Base16, Base32, and Base64 Data Encodings
Base64 encoding and decoding
Примечания по кодировке символов: ASCII, Unicode и UTF-8
Подробный Unicode и JavaScript
Начало работы с кодировкой Base64 Принцип Base64
Подробно объясните принцип base64.
Одна статья для понимания кодировки base64
Кое-что о base64 в JS
Принцип, реализация и применение Base64
Отношения преобразования изображения и Base64
[Вы действительно знаете Unicode и UTF-8?]
Подробное объяснение кодировки UTF-8 и UTF-16 в Unicode.
Таблица соответствий Unicode
Подробная карта исходного кода JavaScript