写点什么

深入理解 Base64 编码原理

作者:秃头小帅oi
  • 2025-03-18
    福建
  • 本文字数:3184 字

    阅读完需:约 10 分钟

前言

今天我们来详细了解一下Base64的编码原理以及应用场景。

通过这篇文章你能够学习到:

  • 什么是 Base64,为什么需要 Base64?

  • Base64 的编码原理

  • Base64 的应用场景

什么是 Base64?

Base64 是一种用于传输 8bit 字节数据的编码方式,Base64 的字符集包含 64 个字符(A-Z、a-z、0-9、+、/)以及补位的=

⚠️需要注意的是它只是一种编码方式,并不是加密方式!!!因为对于Base64来讲,它没有密钥的概念,这意味着任何人都能轻松地将Base64编码的数据还原为原始字符。

尽管如此,不少人仍误将其当作加密工具来使用,这在具备基本技术知识的人眼中,无异于未加密处理...

为什么需要 Base64 编码?

Base64编码最初主要应用于邮件传输协议中,由于这些协议仅支持ASCII字符的传递,导致直接传输二进制文件(如图片、视频等)成为不可能。为了解决这一问题,Base64 被设计出来,它能够将二进制文件内容转换成仅包含 ASCII 字符的编码形式,从而实现在邮件传输协议中安全、有效地传递二进制数据。

编码原理

Base64 编码的核心原理是将输入数据(多为二进制形式)转换成特定字符序列。具体步骤为:首先将输入数据分割成每三个字节(共 24 位)一组,接着将这 24 位分割为四个 6 位的块(因为 Base64 中每个字符代表 6 位二进制数据)。最后,通过查找表将这些 6 位块映射为相应的 Base64 字符。

base64 字符集

上面我们提到标准的Base64一般包含 64 个字符再加一个补位的=

  • 大写字母:A-Z(26 个字符)

  • 小写字母:a-z(26 个字符)

  • 数字:0-9(10 个字符)

  • 特殊字符:+ 和 /(2 个字符)

  • 补位字符:=

编码步骤

  1. 分组:将输入数据按每三个字节一组进行划分,每组组成一个 24 位的二进制数据块。

  2. 分割:将每个 24 位的数据块进一步分割成四个 6 位的数据块。

  3. 字符映射:通过查找字符集,将每个 6 位数据块映射为字符集中的对应字符。

  4. 填充处理:若输入数据的字节数非 3 的倍数,则在数据末尾添加=字符作为填充,以确保编码结果的长度符合 Base64 规范。

怎么理解这些步骤?

以南玖的拼音为例

首先将字符对应的二进制位表示出来



刚好nan是 3 个字节,它们的二进制位正好组成了一个 24 位的二进制块

接着把这个二进制块分割成 4 个 6 位的数据块



最后通过查找 Base64 编码对照表,找到每个 6 位数据块对应的字符



最终nan编码为bmFu

由于nan的字节数正好是 3 的倍数,所以它不需要补位,编码后也就不会出现=

补位

如果字节数不是 3 的倍数,那么余数可能是 1 或 2,所以补位也需要分两种情况。

  • 余数为 1,二进制末尾补 4 个 0,最后多出来的这个字符会编码成 2 个 base64 字符,最后再补两个=

比如宋的拼音song,余数为 1



在这基础上最后还得补上 2 个=,最终song编码为c29uZw==

  • 余数为 2,二进制末尾补 2 个 0,编码后末尾再补 1 个=

比如ab,余数为 2



最终ab编码为YWI=

验证

在 javaScript 中可以调用btoa来进行base64编码



动手实现一下 Base64 编解码

base64 编码

// 自定义base64编码const customEncrypt = (str: string) => {    // base64字符集    const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='    // 将字符串转中的每个字符转换成8位二进制    const binaryStr = str.split('').map(char => {        const binary = char.charCodeAt(0).toString(2)        return binary.padStart(8, '0')    }).join('')    // 将二进制字符串按6位分割    const binaryArr = binaryStr.match(/.{1,6}/g) || []    // 如果最后一组不是6位的倍数,后面补0    const last = binaryArr[binaryArr.length - 1]    if(last?.length % 6 !== 0) {        binaryArr[binaryArr.length - 1] = last.padEnd(6, '0')    }    // 将6位的二进制转换成10进制    const decimalArr = binaryArr.map(binary => parseInt(binary, 2))    // 根据10进制的值获取base64字符    let base64Str = decimalArr.map(decimal => base64Chars[decimal]).join('')    // 补位    while(base64Str.length % 4 !== 0) {        base64Str += '='    }    return base64Str}
复制代码

基本按照上面的编码步骤实现即可

验证

console.log('btoa', btoa('song'))console.log('自定义编码', customEncrypt('song'))
复制代码



base64 解码

解码的过程基本就是与编码反过来

// 自定义base64解码const customDecrypt = (str: string) => {    // base64字符集    const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='    // 将base64字符转换成10进制    const decimalArr = str.split('').map(char => base64Chars.indexOf(char))    // 将10进制转换成6位二进制    const binaryArr = decimalArr.map(decimal => decimal.toString(2).padStart(6, '0'))    // 将6位的二进制拼接    const binaryStr = binaryArr.join('')    // 将8位的二进制转换成字符    const charArr = binaryStr.match(/.{1,8}/g) || []    return charArr.map(binary => String.fromCharCode(parseInt(binary, 2))).join('')}
复制代码

验证

console.log('atob', atob('c29uZw=='))console.log('自定义解码', customDecrypt('c29uZw=='))
复制代码



思考🤔

按照这个思路我们是不是可以实现一个比Base64更安全的伪加密方法

比如:

  • 更换字符集

  • 更换二进制分割手段

应用场景

数据传输

Base64 编码是一种在 HTTP 文本协议中传输二进制数据的常用方法。由于 HTTP 协议本质上是基于文本的,它限制了只能传输可打印的 ASCII 字符(范围从 32 到 126),这包括字母、数字、标点符号和一些特殊符号。然而,二进制数据包含许多不在这个范围内的字符,因此无法直接通过 HTTP 协议进行传输。Base64 编码不仅解决了在 HTTP 协议中传输二进制数据的问题,还确保了数据的完整性和可读性。

数据存储

Base64 编码常用于存储二进制数据,如数据库中的图像、文件等,因为它将数据转换为可打印字符,避免了二进制数据在存储过程中可能出现的问题。

在前端页面实现中,为了提高加载效率,简单图片通常会选择直接内嵌而非加载外部资源。然而,图片是二进制数据,直接嵌入并不简单。幸运的是,现代浏览器普遍支持Data URLs功能,该功能通过 Base64 编码将图片或其他文件的二进制数据转换为文本字符串,从而可以方便地嵌入到网页中。这样,就无需进行额外的外部资源加载,有助于减少页面加载时间。

协议编码

Base64编码最初主要应用于邮件传输协议中,由于这些协议仅支持ASCII字符的传递,导致直接传输二进制文件(如图片、视频等)成为不可能。为了解决这一问题,Base64 被设计出来,它能够将二进制文件内容转换成仅包含 ASCII 字符的编码形式,从而实现在邮件传输协议中安全、有效地传递二进制数据。

总结

Base64 编码是一种广泛应用的编码方法,它将二进制数据转换为可打印的 ASCII 字符集,特别适用于数据传输和存储场景。然而,重要的是要认识到,Base64 编码本身并不具备数据加密或安全保护的功能。在需要处理敏感信息时,仅凭 Base64 编码是远远不够的,必须结合适当的加密技术和安全传输协议(如 HTTPS)来确保信息的安全性和隐私性。

行业拓展

分享一个面向研发人群使用的前后端分离的低代码软件——JNPF

基于 Java Boot/.Net Core 双引擎,它适配国产化,支持主流数据库和操作系统,提供五十几种高频预制组件,内置了常用的后台管理系统使用场景和实用模版,通过简单的拖拉拽操作,开发者能够高效完成软件开发,提高开发效率,减少代码编写工作。

JNPF 基于 SpringBoot+Vue.js,提供了一个适合所有水平用户的低代码学习平台,无论是有经验的开发者还是编程新手,都可以在这里找到适合自己的学习路径。

此外,JNPF 支持全源码交付,完全支持根据公司、项目需求、业务需求进行二次改造开发或内网部署,具备多角色门户、登录认证、组织管理、角色授权、表单设计、流程设计、页面配置、报表设计、门户配置、代码生成工具等开箱即用的在线服务。

用户头像

摸个鱼,顺便发点有用的东西 2023-06-19 加入

互联网某厂人(重生版)

评论

发布
暂无评论
深入理解Base64编码原理_秃头小帅oi_InfoQ写作社区