使用方法
- 「待转换文本」默认写着一句
Hello, 柳泉工具!,改成你自己的内容即可;改完按 Ctrl+Enter(Mac 上是 Cmd+Enter)重新生成,框被清空时点「生成 data URI」会把示例填回去。 - 「媒体类型」下拉给出四种常见写法:text/plain;charset=utf-8、text/html、image/svg+xml、application/json,也可选「自定义」自己填。
- 「编码方式」二选一。base64 把任意字节压进 A-Za-z0-9 加号斜杠这 64 个字符再加等号补位,任何内容都能安全通过;百分号编码保留原文的可读性,代价是每个非 ASCII 字节变成三个字符。
- 「长度上限(字符)」默认 100000,最小 100、最大 100000、步长 100。文本超过它不会硬截断,而是给出写明当前长度的提示——data URI 太长本来就会被截断。
- 结果区先给一行结论,下面是完整的 data URI,再下面是五格统计:原始字节数、编码后字符数、膨胀倍数、前缀长度、URI 总长度。
- 统计下面是一张 24 行长度阶梯表,从 1 字节列到 16 MB,逐行给出 base64 字符数与两种口径的百分号字符数;默认显示 12 行,点「加载更多」展开全部,点「导出 CSV」存成带 BOM 的文件。
- 「复制 URI」把整串 data URI 放进剪贴板;「复制对照表」复制正文里的字符编码对照表,制表符分隔可直接粘进表格软件。
- 文本区为空时点生成会自动填回示例;自定义类型为空、不含斜杠、含逗号或空格、文本超长,都会给出写明原因的提示,不会拿上一次的结果冒充本次输出。
这个文本转数据URI转换器能解决什么问题
把一段文本变成可以直接嵌进文档的字符串,是前端模板、邮件模板与单文件交付里反复出现的小需求。RFC 2397 给 data 这个方案下的定义是 data:[<mediatype>][;base64],<data>,两段方括号都可省略,省略媒体类型时按 text/plain;charset=US-ASCII 处理。这一页做的就是按这条语法把文本就地拼成 URI。
第一类是内联小资源。一个几十字节的 SVG 图标、一段 JSON 配置,单独发一次请求的握手成本远高于内容本身,写成 data URI 直接塞进 url() 就能省掉这次往返。SVG 与 HTML 这类文本格式还有额外好处:可以不用 base64,直接百分号编码,人还能读懂里面的标签。
第二类是单文件交付。把一个页面连同它依赖的说明文本、配置与图标打成一个文件,发给别人双击就能打开,不需要附带目录。这类场景对体积敏感,本页把两种编码的长度并排列出来,就是为按内容挑更短的那种。
第三类是邮件与富文本模板。部分邮件客户端不接受外链图片与外链样式,把小图标转成 data URI 是绕开限制的常用做法。但要注意 data:text/html;base64, 能承载可执行脚本,属于 XSS 载体,用在别人能控制内容的场合风险极高。
第四类是判断到底该用哪种编码。纯 ASCII 时百分号编码是 1 倍、base64 是 1.33333333333 倍,百分号更短;内容是中文时百分号变成 3 倍、base64 仍是 1.33333333333 倍,base64 反而更短。同一决策在两种内容下结论相反,靠猜很容易选错。
计算原理与变量说明
data URI 只有三段。第一段是 scheme 与可选的媒体类型,形如 data:text/plain;charset=utf-8;第二段是可选的 ;base64 标记,只在写了媒体类型之后才出现,写成 mediatype;base64,若媒体类型整段省略则要写成 data:;base64,...;第三段是逗号之后的数据本体。
base64 的换算很机械:每 3 个字节编成 4 个字符,体积上限是 1.33333333333 倍,也就是多出 33.33 个百分点。除不尽的余数靠等号补位——余 1 字节补两个等号、余 2 字节补一个、整除补零个。补位让小数据上的倍率明显高于 1.333:1 字节编成 4 字符是 4 倍,10 字节编成 16 字符是 1.6 倍,1 KB(1024 字节)编成 1368 字符是 1.33594 倍,1 MB 编成 1398104 字符,已非常接近极限值。
百分号编码的换算方向相反,它按字节工作:一个字节变成一个百分号加两位十六进制,占 3 个字符。纯 ASCII 时每个字符恰好一个字节,长度不变,是 1 倍;UTF-8 下一个汉字占 3 个字节,百分号编码后是「百分号 XX」重复三次共 9 个字符,膨胀到 3 倍。「中文」这两个字原始 6 字节,百分号编码后是 18 个字符,正是 3 倍。
于是两种编码的优劣完全由内容决定:ASCII 占多数时百分号更短,非 ASCII 占多数时 base64 更短。分界线并不神秘——百分号对每个非 ASCII 字节收 3 个字符,base64 对每个字节一律收 1.33333333333 个字符,非 ASCII 比例越过某个点,base64 就会反超。
| 媒体类型 | 推荐编码 | 说明 |
|---|---|---|
| text/plain;charset=utf-8 | 百分号编码 | 纯文本多数字符不需要转义,可读性最好 |
| text/html | 百分号编码 | 标签结构可保留;含大量特殊字符时改 base64 |
| image/svg+xml | 百分号编码 | 尖括号与引号必须转义,其余可读 |
| application/json | 百分号编码 | 引号与花括号转义后仍能辨认字段 |
| image/png | 必须 base64 | 二进制流,百分号编码会膨胀到 3 倍 |
| font/woff2 | 必须 base64 | 二进制流,且体积大,超过几十 KB 建议改用 blob |
安全边界要单独说。data:text/html;base64, 里可以放完整的 HTML 与脚本,因此它是 XSS 的常见载体,内容安全策略的 default-src 指令会拦下来自 data: 的脚本。另一方面,Chrome 60 与 Firefox 59 之后浏览器禁止顶级导航到 data: URL:在地址栏粘贴或用脚本打开 data: 地址会被拒绝,只有 img、iframe、CSS url() 这类子资源加载仍然可用。
最后是它与 blob: URL 的分工。data: 是内联字符串,同步可用、不需要显式释放,但复制一份就多占一份内存;blob: 是对内存中对象的引用,用完必须调用 revokeObjectURL 释放,否则那块内存不会被回收。体积超过几十 KB 时 blob: 通常更合适。
完整示例(数值仅作演示)
打开页面时的默认值是文本 Hello, 柳泉工具!、媒体类型 text/plain;charset=utf-8、编码 base64、长度上限 100000。这句文本共 12 个字符、20 个字节(8 个 ASCII 字符加 4 个汉字,每个汉字 3 字节);base64 编码后是 28 个字符 SGVsbG8sIOafs+azieW3peWFtyE=,末尾一个等号补位,因为 20 除以 3 余 2。完整 URI 前缀 37 个字符,总长 65 个字符。
把编码方式切到百分号编码,同一句变成 48 个字符 Hello%2C%20%E6%9F%B3%E6%B3%89%E5%B7%A5%E5%85%B7!:逗号变 %2C、空格变 %20、四个汉字各占 9 个字符。48 比 28 长了 20 个字符,膨胀 2.4 倍,中文占多数时 base64 的优势一目了然。
换成纯 ASCII 的 Hello, world!,结论立刻反过来:13 个字节,base64 编成 20 字符,百分号编码只有 17 字符(Hello%2C%20world!)。同一套规则,内容一换,更短的那一边就换了人。
文本与 data URI 对照表
下表列出常见字符在百分号编码下的写法。base64 的优势正在于这些字符全都不出现在它的字符集里,不需要处理任何保留字符。
| 字符 | 百分号编码 | 是否需要转义 |
|---|---|---|
| 空格 | %20 | 必须,空格会截断 URI |
| 逗号 , | %2C | 必须,逗号是前缀与数据的分界 |
| 冒号 : | %3A | 视位置而定,媒体类型里的冒号保留 |
| 斜杠 / | %2F | 必须,避免被当成路径 |
| 分号 ; | %3B | 建议转义,分号是参数分隔符 |
| 加号 + | %2B | 建议转义,form 口径下会被解成空格 |
| 百分号 % | %25 | 必须,否则被当成转义起始 |
| 井号 # | %23 | 必须,井号之后是片段标识 |
| 双引号 " | %22 | 必须,塞进 HTML 属性时会打断属性 |
| 小于号 < | %3C | 必须,否则被当成标签起始 |
| 汉字「柳」 | %E6%9F%B3 | 必须,一个汉字 3 字节共 9 个字符 |
| 等号 = | %3D | 建议转义,易与查询串混淆 |
第二张表给出 base64 的长度阶梯,按每 3 字节编成 4 字符的规则算出,用来估算稍大的资源会不会超预算。
| 原始字节 | base64 字符 | 膨胀(倍) |
|---|---|---|
| 1 | 4 | 4.00000 |
| 10 | 16 | 1.60000 |
| 64 | 88 | 1.37500 |
| 128 | 172 | 1.34375 |
| 256 | 344 | 1.34375 |
| 512 | 684 | 1.33594 |
| 1024 | 1368 | 1.33594 |
| 2048 | 2732 | 1.33398 |
| 4096 | 5464 | 1.33398 |
| 8192 | 10924 | 1.33350 |
| 16384 | 21848 | 1.33350 |
| 32768 | 43692 | 1.33337 |
结果边界、舍入与适用说明
- 文本区被清空时不会报错,而是把示例
Hello, 柳泉工具!填回去再算。 - 选了「自定义」而输入框为空时提示媒体类型不能为空;不含斜杠、含逗号或含空格时分别给出对应提示,不自动补 text/plain。
- 文本字符数超过上限时报出当前字符数与上限值,不静默截断——截断后的 data URI 会让对端解析出半截内容。
- 长度上限留空、写成小数或超出 100 到 100000 时分别给出对应提示,不套默认值,也不自动取整。
- 膨胀倍数按「编码后字符数 ÷ 原始字节数」算,除数为零时记 0;等号补位让小数据越偏离 1.33333333333。
- 百分号编码列给出两种口径:纯 ASCII 是 1 倍,UTF-8 中文是 3 倍。真实内容往往两者混合,实际长度落在两列之间。
- 「尝试在新标签打开」被浏览器拦截属正常:Chrome 60 与 Firefox 59 之后禁止顶级导航到 data: URL。
- 历史限制仅供参考:IE8 对 data URI 限 32 KB(32768 字符)。现代浏览器没有这个硬限制,但服务器与邮件网关仍可能按自己的上限截断。
常见问题
data URI 里的媒体类型能省略吗?
能。RFC 2397 里媒体类型与 base64 标记都在方括号中,都是可选的。省略时按 text/plain;charset=US-ASCII 处理,非 ASCII 字符会失去编码声明,写中文请带上 charset=utf-8。
;base64 标记一定要跟在媒体类型后面吗?
是的。语法是 mediatype;base64,分号是媒体类型的参数分隔符。若媒体类型整段省略又要用 base64,得写成 data:;base64,...,分号直接跟在冒号后面。
base64 为什么总是多出三分之一的体积?
它把 3 个字节(24 位)重新切成 4 个 6 位组,每个 6 位组用一个可打印字符表示,字节数与字符数之比恒为 3 比 4,即膨胀 1.33333333333 倍。小数据上还会多出等号补位,倍数更高一些。
中文内容到底该用 base64 还是百分号编码?
用 base64。UTF-8 下一个汉字 3 字节,百分号编码后是 9 个字符,膨胀 3 倍;base64 对任何字节都只收 1.33333333333 倍。反过来,纯 ASCII 内容用百分号编码是 1 倍,比 base64 短,而且人还能读懂。
为什么在新标签里打不开生成的 data URI?
Chrome 60 与 Firefox 59 之后,浏览器禁止顶级导航到 data: URL,这是针对钓鱼与混淆攻击的统一限制。img 的 src、iframe 的 src、CSS 的 url() 这些子资源加载不受影响。
把 HTML 转成 data URI 安全吗?
内容本身可控就没问题,但 data:text/html;base64, 能承载脚本,属于典型的 XSS 载体。若内容里掺入用户输入,务必先转义;站点层面可以用内容安全策略的 default-src 指令拦下来自 data: 的脚本。
多大的内容适合做成 data URI?
经验值在几十 KB 以内。IE8 时代硬上限是 32 KB(32768 字符),现代浏览器没有这个限制,但服务器、邮件网关与剪贴板各有自己的上限。超过这个量级请改用 blob: URL 或外链文件。
输入的内容会上传到服务器吗?
不会。文本、媒体类型与编码选项只在本页脚本里参与运算,页面没有发起任何网络请求,刷新后输入即回到默认示例。