news 2026/5/25 20:10:01

Base64 编码 URI/URL 详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Base64 编码 URI/URL 详解

Base64 编码 & URI/URL 详解


一、Base64 是什么

1.1 一句话定义

Base64 是一种把二进制数据转换成纯文本的编码方式。用 64 个可打印字符(字母、数字、+/)来表示任意字节数据。

1.2 为什么需要它

计算机里很多数据是二进制的——图片、音频、加密密钥、Protobuf 消息等。但很多传输协议只支持文本:

协议/场景限制
JSON只能传 UTF-8 文本,不能传原始字节
HTTP Header纯 ASCII,二进制值会出错
SMTP(邮件)最早只支持 7-bit ASCII
HTML<img>src必须是 URL 或 Data URI

Base64 就是翻译器:把"机器读的字节"翻成"协议能传送的字符串"。

1.3 在我的项目里干什么用

本地 test.png → [二进制 PNG 数据] → Base64 编码 → "iVBORw0KGgo..." ↓ 塞进 JSON body 发给火山引擎 API ↓ 服务器反向解码还原图片

没有 Base64,你就得先把图片上传到 OSS,拿到 URL,再把 URL 传给 API——多一步。Base64 让你直接把本地文件"嵌入"请求里。


二、Base64 是怎么编出来的

2.1 核心思想:3 字节 → 4 字符

原始: 3 个字节 = 24 个比特 Base64: 24 个比特 ÷ 6 = 4 个字符

每个 Base64 字符代表 6 个比特(0-63),对应字符集里的一个位置。

2.2 字符集(64 个字符)

索引 字符 索引 字符 索引 字符 索引 字符 0 A 16 Q 32 g 48 w 1 B 17 R 33 h 49 x 2 C 18 S 34 i 50 y 3 D 19 T 35 j 51 z 4 E 20 U 36 k 52 0 5 F 21 V 37 l 53 1 6 G 22 W 38 m 54 2 7 H 23 X 39 n 55 3 8 I 24 Y 40 o 56 4 9 J 25 Z 41 p 57 5 10 K 26 a 42 q 58 6 11 L 27 b 43 r 59 7 12 M 28 c 44 s 60 8 13 N 29 d 45 t 61 9 14 O 30 e 46 u 62 + 15 P 31 f 47 v 63 /

2.3 手动编码示例

"Man"三个字符编成 Base64:

步骤 1: 取每个字符的 ASCII 码 M → 77 (0x4D) → 01001101 a → 97 (0x61) → 01100001 n → 110 (0x6E) → 01101110 步骤 2: 拼成 24 位二进制流 01001101 01100001 01101110 步骤 3: 切成 4 个 6 位 010011 010110 000101 101110 ↓ ↓ ↓ ↓ 步骤 4: 每 6 位转成十进制 (0-63) 010011 → 19 010110 → 22 000101 → 5 101110 → 46 步骤 5: 查字符集 19 → T 22 → W 5 → F 46 → u 结果: "TWFu"

2.4 填充规则(=号)

当原始字节数不是 3 的倍数时:

剩余字节数填充
1 字节(8 位)取 6 位 + 填 2 个零 → 2 个 Base64 字符 +==
2 字节(16 位)取 12 位 → 3 个 Base64 字符 +=
3 字节(24 位)刚好 4 个字符,不填

示例:只编码一个字节M(77) → 01001101

010011 01.... ← 只有 8 位,后 4 位不存在 010011 010000 ← 后面填 0000 凑够 12 位 ↓ ↓ 19 16 T Q 结果: "TQ==" (两个 `=` 表示"原始数据只有 1 字节,解码时忽略填充位")

三、URI 和 URL 的关系

3.1 一句话

URL 是 URI 的一种。URI 是"标识某个资源",URL 在 URI 的基础上多了"怎么获取它"。

3.2 层级关系

URI (Uniform Resource Identifier - 统一资源标识符) ├── URL (Uniform Resource Locator - 统一资源定位符) │ "这个资源在哪里、怎么拿到" │ 例: https://example.com/photo.png │ 文件::///home/user/photo.png │ ftp://server/file.zip │ └── URN (Uniform Resource Name - 统一资源名称) "这个资源叫什么名字(但不告诉你它在哪)" 例: urn:isbn:0-486-27557-4 (一本书的 ISBN) urn:uuid:6e69285a-1461-459e... (一个 UUID)

3.3 关键区别

URIURLURN
概念“资源叫这个”“去这里拿”“它就叫这个名字”
是否包含位置不一定必须不包含
能直接访问吗不一定不能
例子https://a.com/x.png
data:image/png;base64,...
urn:isbn:0451450523
mailto:hi@example.com

所有 URL 都是 URI,但不是所有 URI 都是 URL。

3.4 Data URI 的特殊位置

Data URI 是最特殊的一类 URI:

data:image/png;base64,iVBORw0...
  • 是 URI:唯一标识了一个资源(这张图片)
  • 不是 URL:没有告诉你去哪里下载,资源就在字符串本身里
  • 不是 URN:没有给资源命名,而是直接附带了完整数据

可以理解为自包含的 URI——资源即是标识符,标识符即是资源。

3.5 你项目里两个 URI 的对比

// 请求中:告诉 API "参考图长这样""data:image/png;base64,iVBORw0KGgo..."// Data URI (非 URL)// ↑ 图片数据直接嵌在字符串里// 响应中:API 返回 "生成结果在这里""https://ark-volces.com/tmp/abc123.png"// URL (也是 URI)// ↑ 指向远程服务器上的一个文件

四、C++ 中实现 Base64 编码

4.1 完整实现(零依赖,~15 行)

conststd::string BASE64_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";std::stringbase64_encode(constunsignedchar*data,size_t len){std::string result;result.reserve(4*((len+2)/3));// 预分配,避免反复扩容for(size_t i=0;i<len;i+=3){// 把最多 3 个字节拼成 24 位整数unsignedintn=(unsignedint)data[i]<<16;if(i+1<len)n|=(unsignedint)data[i+1]<<8;if(i+2<len)n|=(unsignedint)data[i+2];// 24 位切成 4 个 6 位,查表得到 4 个字符result.push_back(BASE64_CHARS[(n>>18)&0x3F]);// 位[23:18]result.push_back(BASE64_CHARS[(n>>12)&0x3F]);// 位[17:12]result.push_back((i+1<len)?BASE64_CHARS[(n>>6)&0x3F]// 位[11:6]:'=');// 填充result.push_back((i+2<len)?BASE64_CHARS[n&0x3F]// 位[5:0]:'=');// 填充}returnresult;}

4.2 逐行解释

预分配:

result.reserve(4*((len+2)/3));
len(len+2)/3× 4含义
1141 字节 → 4 字符(含==
2142 字节 → 4 字符(含=
3143 字节 → 4 字符
4284 字节 → 8 字符
10034136100 字节 → 136 字符

(len+2)/3ceil(len/3)的整除技巧。

24 位拼接:

unsignedintn=(unsignedint)data[i]<<16;if(i+1<len)n|=(unsignedint)data[i+1]<<8;if(i+2<len)n|=(unsignedint)data[i+2];
位[23:16] ← data[i] 位[15:8] ← data[i+1] (如果存在) 位[7:0] ← data[i+2] (如果存在)

6 位切片 + 查表:

24 位: [23:18] [17:12] [11:6] [5:0] ↓ ↓ ↓ ↓ 操作: >>18 >>12 >>6 >>0 掩码: &0x3F &0x3F &0x3F &0x3F

>>18 & 0x3F意思是"向右移 18 位,只保留最低 6 位"。

0x3F=00111111(二进制)= 63(十进制),刚好取低 6 位。

条件填充:

(i+1<len)?BASE64_CHARS[...]:'='
  • 原始第 2 个字节不存在 → 输出=
  • 原始第 3 个字节不存在 → 输出=
  • 解码时看到=就知道:这轮只有 1 或 2 个真实字节

4.3 解码实现(对称反向)

std::vector<unsignedchar>base64_decode(conststd::string&encoded){// 构建反向查找表: 字符 → 6 位值intreverse[256]={};for(inti=0;i<64;i++){reverse[(unsignedchar)BASE64_CHARS[i]]=i;}std::vector<unsignedchar>result;result.reserve(encoded.size()*3/4);intval=0,bits=-8;for(unsignedcharc:encoded){if(c=='=')break;// 遇到 = 停止val=(val<<6)|reverse[c];// 每 6 位拼进 24 位缓冲区bits+=6;if(bits>=0){result.push_back((val>>bits)&0xFF);// 取出一个完整字节bits-=8;}}returnresult;}

五、Base64 的主要用途

5.1 用途总览

场景举例
API 传图片/文件图生图 API 的image字段(就是你的项目)
Data URI 内嵌HTML<img src="data:image/png;base64,...">
邮件附件MIMEContent-Transfer-Encoding: base64
JWT TokeneyJhbGci...的 header/payload 部分
密钥存储SSH 公钥-----BEGIN PUBLIC KEY-----
URL 安全传输二进制 ID 转成 URL-safe 字符串(+/-_
配置文件k8s Secret 里的证书、docker registry 认证

5.2 为什么不用 Base16 (hex)

Base16Base64
开销膨胀 100%(1 字节 → 2 字符)膨胀 33%(3 字节 → 4 字符)
示例FF00AB12.../wCrEg...
优点人眼直接可读更紧凑

Base64 是"可读性"和"体积"之间的最优折中。

5.3 常见变体

变体区别用途
标准 Base64+/=填充JSON、XML、一般场景
URL-Safe Base64+/-_,去掉=URL 参数、文件名、JWT
Base64 without padding省略尾部=节省几个字符

六、一张图总结

┌─────────────────────────────────────────────────────────┐ │ URI (标识资源) │ │ ┌──────────────────────┐ ┌──────────────┐ │ │ │ URL (定位资源) │ │ URN (命名资源)│ │ │ │ │ │ │ │ │ │ https://x.com/a.png │ │ urn:isbn:123 │ │ │ │ file:///home/a.png │ │ │ │ │ └──────────────────────┘ └──────────────┘ │ │ │ │ ┌──────────────────────────┐ │ │ │ Data URI (自包含资源) │ 不属于 URL 也不属于 URN │ │ │ │ │ │ │ data:image/png;base64, │ │ │ │ iVBORw0KGgoAAAA... │ │ │ │ ─────────── ────────── │ │ │ │ 告诉服务器: 实际图片 │ │ │ │ "这是PNG" 数据编码 │ │ │ └──────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ Base64 编码过程: 原始图片 (二进制) → [3字节一组] → [4字符] → JSON 文本 ↓ ↓ ↓ ↓ 无法直接塞 JSON 切成 24 位 查表映射 拼进 body "iVBORw0..."
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/25 20:08:26

关闭SSH密码登录:公钥认证实战指南与安全加固

1. 为什么关掉密码登录是服务器安全的第一道硬门槛我第一次在凌晨三点被短信惊醒&#xff0c;是监控系统告警&#xff1a;某台对外暴露的测试服务器在五分钟内遭遇了237次SSH暴力破解尝试&#xff0c;IP来自三个不同国家的动态出口节点。登录后发现&#xff0c;虽然没被攻破——…

作者头像 李华
网站建设 2026/5/25 20:07:42

5A智慧景区建设|对标一流!巨有科技打造数智化标杆景区

5A级景区是中国旅游的最高标准&#xff0c;代表着服务与管理的顶尖水平。随着5A评审标准日益严苛&#xff0c;“智慧化”已成为核心硬性指标。然而&#xff0c;不少景区的智慧化建设陷入“重硬件、轻整合”的误区&#xff0c;系统林立、数据孤岛&#xff0c;投入巨大却效果不佳…

作者头像 李华
网站建设 2026/5/25 20:06:00

创建上三角矩阵和下三角矩阵

在“创建对角矩阵”中得到的对角矩阵是除主对角线以外的元素都为零的矩阵&#xff0c;这篇博文要创建的两类矩阵也有一部分元素为零。上三角矩阵的主对角线下方元素全为零&#xff0c;下三角矩阵的主对角线上方元素全为零。先创建一个矩阵A&#xff0c;再用triu(A)和tril(A)即可…

作者头像 李华
网站建设 2026/5/25 20:02:49

agent-skills安全渗透测试:五维验证与自动化审计实践

1. 这不是黑客电影&#xff0c;而是真实渗透测试现场&#xff1a;agent-skills框架下的安全验证逻辑“agent-skills”这个词在当前技术圈里常被误读为某种AI智能体的“技能插件库”&#xff0c;但实际它是一套面向自动化安全验证场景设计的轻量级能力编排框架——核心定位不是生…

作者头像 李华
网站建设 2026/5/25 20:02:37

ChromeDriver与Chrome版本精确匹配指南:破解session not created错误

1. 为什么一个WebDriver版本号能让你加班到凌晨两点 去年冬天&#xff0c;我接手了一个电商比价爬虫项目的交接。前任同事留下的代码只有一行注释&#xff1a;“ChromeDriver 114 跑得稳”。我信了——直到上线前夜&#xff0c;CI流水线突然报错&#xff1a; session not crea…

作者头像 李华
网站建设 2026/5/25 20:01:05

终极指南:用D2DX让《暗黑破坏神2》在现代电脑上焕发新生

终极指南&#xff1a;用D2DX让《暗黑破坏神2》在现代电脑上焕发新生 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 还在为经…

作者头像 李华