[指南] 10 min read

[指南] 深入理解 Data URI:data:image/png;base64,... 完整解析

一份关于 data: URI 方案的实战指南——逐字段解读 data:image/png;base64,iVBORw0KGgo... 中每个部分的真正含义,什么时候内联是正确选择,什么时候它会反过来咬你一口。

April 2026 | fundamentals

// data: URI 究竟是什么

data: URI 是一种 URI 方案——和 https: 或 file: 同属一类——它把资源本身直接嵌入到 URI 字符串里,而不是指向某个远程位置。它由 RFC 2397 定义,允许你把一小段二进制或文本数据当作 URL 来使用。

在实际项目里最常见的形式就是图片场景:data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...。浏览器看到这个 URL 后,读取 MIME 类型,把 Base64 负载解码回字节,然后渲染图片——整个过程不会发出任何 HTTP 请求。

// 一段语法,逐字段拆解

完整语法是 data:[<mediatype>][;base64],<data>。三个可选部分,加上一个必需的分隔符(逗号)。我们用真实示例拆开看:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUg... 从左往右读:
data: —— 方案本身。告诉解析器:“资源就在 URL 内部,无需再去 fetch”。
image/png —— MIME 类型。告诉渲染器如何解释负载内容。如果省略,默认是 text/plain;charset=US-ASCII
;base64 —— 编码标识。表明负载是 Base64 编码(RFC 4648)。如果不写,负载会被当作 URL 编码的文本。
, —— 元数据与负载之间必需的分隔符。
iVBORw0KGgo... —— 真正的 Base64 编码后的图片字节流。

// Anatomy diagram
// data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...
// │    │         │      │
// │    │         │      └── Base64 payload (the actual image bytes)
// │    │         └────────── encoding flag (always 'base64' for binary)
// │    └──────────────────── MIME type (optional, defaults to text/plain)
// └───────────────────────── scheme literal (always 'data:')

// data: URI 为什么存在

人们抛弃普通图片 URL 转而使用 data URI,主要有三个原因:

1. 消除一次 HTTP 请求。页面上每个 <img src="..."> 都要付一次网络往返的代价。对于一个小小的图标或者雪碧图,光是这次往返花的时间,可能比传输字节本身还长。把图片以 data URI 形式内联进 HTML/CSS,就把请求彻底消除了。在 HTTP/1.1 时代这一点尤其重要;HTTP/2 多路复用之后影响小了一些,但对首屏关键图标依然有用。

2. 让资源自包含。HTML 邮件需要在默认屏蔽远程图片的客户端(Gmail、Outlook)里也能渲染出来。一份你发给客户的静态报告,即便离线也得能显示公司 Logo。一段 Bookmarklet 需要一个能在复制粘贴中存活下来的图标。一段文档片段需要让截图随 Markdown 一起流转。在所有这些场景里,图片必须 住进文档里——而 data URI 正是为此而生的方式。

3. 程序化生成。代码在运行时生成一张图片——一个二维码、一张图表、一块签名画布——你需要立刻把它显示出来,而不必先上传到服务器再换回一个 URL。canvas.toDataURL('image/png') 直接把 data URI 递到你手上;赋值给 img.src,就是最简单的工作流。

// 你真正会遇到的 MIME 类型清单

MIME 类型这一格可以填任何媒体类型,但实际项目中你常打交道的就那几种图片类型:

image/png —— 最常见。无损,支持透明通道。Base64 以 iVBORw0KGgo 开头。
image/jpeg —— 照片和截图。有损。Base64 以 /9j/ 开头。
image/gif —— 老旧及动图场景。Base64 以 R0lGOD 开头。
image/webp —— 现代格式,文件更小。Base64 以 UklGR 开头。
image/svg+xml —— 矢量图。SVG 是文本,所以你既可以用 Base64 编码(加 ;base64),也可以仅做 URL 编码(不加)。URL 编码的 SVG 通常更小。
image/x-iconimage/vnd.microsoft.icon —— Favicon。Base64 以 AAABAA 开头。

<!-- All five types in a single HTML document -->
<img src="data:image/png;base64,iVBORw0KGgo..." alt="PNG inline">
<img src="data:image/jpeg;base64,/9j/4AAQSkZJRg..." alt="JPEG inline">
<img src="data:image/gif;base64,R0lGODlhAQABAA..." alt="GIF inline">
<img src="data:image/webp;base64,UklGRiIAAABXRU..." alt="WebP inline">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxu..." alt="SVG inline">

// 在 HTML、CSS 和 JavaScript 中使用 data: URI

凡是允许填 URL 的位置,data URI 都可以照常使用。

<!-- HTML <img> tag -->
<img src="data:image/png;base64,iVBORw0KGgo..." width="32" height="32" alt="icon">

<!-- HTML <link> for favicon -->
<link rel="icon" href="data:image/x-icon;base64,AAABAAEAEBA...">

/* CSS background-image */
.button-icon {
  background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxu...');
  background-size: 16px 16px;
}

/* CSS @font-face — yes, fonts work too */
@font-face {
  font-family: 'InlineFont';
  src: url('data:font/woff2;base64,d09GMgAB...') format('woff2');
}

// JavaScript — assign directly to img.src
const img = new Image();
img.src = 'data:image/png;base64,iVBORw0KGgo...';
document.body.appendChild(img);

// JavaScript — fetch a data URI like any other URL
const response = await fetch('data:application/json;base64,eyJrZXkiOiJ2YWx1ZSJ9');
const data = await response.json(); // { key: 'value' }

// Canvas、File、Blob → data: URI

浏览器有三个 API 直接把 data URI 递给你,你完全不用自己动手做 Base64:

// 1. Canvas → data URI (instant)
const canvas = document.querySelector('canvas');
const pngDataURI = canvas.toDataURL('image/png');
const jpegDataURI = canvas.toDataURL('image/jpeg', 0.85); // quality 0–1
// pngDataURI === 'data:image/png;base64,iVBORw0KGgo...'

// 2. <input type="file"> → data URI via FileReader
const file = document.querySelector('input[type=file]').files[0];
const reader = new FileReader();
reader.onload = () => {
  // reader.result is the data URI
  document.querySelector('img').src = reader.result;
};
reader.readAsDataURL(file);

// 3. Blob → data URI (manual, but rarely needed — use URL.createObjectURL instead)
const blob = new Blob([bytes], { type: 'image/png' });
const reader2 = new FileReader();
reader2.onload = () => console.log(reader2.result);
reader2.readAsDataURL(blob);
// Or, for in-page display, prefer:
const objectURL = URL.createObjectURL(blob); // 'blob:https://...' — much shorter, no Base64

// 33% 的体积代价(以及它什么时候重要)

Base64 用 4 个 ASCII 字符表示 3 字节二进制,所以编码后的负载长度恰好是 4⌈n/3⌉ 字节——比原文大约多 33%。一张 12 KB 的 PNG 变成大约 16 KB 的 data URI,再加上 data:image/png;base64, 前缀的几字节开销。

这点开销什么时候要紧?
极小资源(小于 4 KB):这 33% 的膨胀,被节省下来的 HTTP 往返完全压过。放心内联。
中等资源(4–50 KB):具体情况具体看。配合 HTTP/2 与缓存,一次单独的请求通常比每次刷新都重新传输内联版本要快。
大资源(50 KB 以上):几乎永远不要内联。data URI 会让所有缓存的 HTML 页面、所有邮件、所有包含它的 JSON 负载都肿起来。请使用单独的 URL。

data URI 没有缓存可言——浏览器没法把字节直接烧进 HTML 里的图片缓存起来。如果同一张图出现在多个页面上,每个页面都要付全部成本。一个普通的 <img src="/logo.png"> 配上 HTTP 缓存头,只要下载一次,处处复用。

// 你迟早会碰到的浏览器上限

浏览器并没有给 data URI 设置统一的硬性上限,但实际可用的天花板的确存在:

Chrome / Edge / Firefox:<img src> 中,data URI 在数 MB 级别都可以工作。超过约 32 MB 时,你会撞到单标签页的内存压力。
Safari:历史上把 <a href>(下载链接)中的 data URI 限制在大约 2 MB。对于 <img>,更大的尺寸也能工作,但渲染会变慢。
Internet Explorer 8:CSS 和 HTML 中的 data URI 上限为 32 KB。(IE9+ 移除了限制,但速度从来都比不上现代浏览器。)
HTTP 请求行:放在 <form action> 或查询字符串里的 data URI,会受浏览器允许的 URL 长度限制(IE 大约 2 KB,其他浏览器 8 KB 以上)。

如果你发现自己已经接近其中任何一个上限,说明这份资源对内联来说太大了。改用普通 URL,或者改用 URL.createObjectURL(blob)——它给你一个短小的 blob: URL,背后是一个你可以一直保留在内存里的 Blob。

// 安全方面的考量

data URI 不走网络,这点很方便——但它也绕过了几条原本默认“内容来自服务器”的 Web 安全机制。

同源策略。在现代 Chrome/Firefox 中,data: URI 在技术上被视作不透明源(opaque origin),所以从 data URI 加载的 JavaScript 无法以无限制的方式访问父文档的 Cookie、localStorage 或 DOM。这一点对沙箱化不可信内容是好事,但同时也意味着,那些依赖 origin 校验的跟踪、统计与 CSRF 防护可能会出问题。

通过 data:text/html 引发的 XSS。用户主动执行的 data:text/html,<script>...</script> 会变成一个拥有完整权限的页面。正因如此,现代浏览器禁止对 data:text/html 进行顶层导航(Firefox 自 2018 年起,Chrome 自 2020 年起)。绝不要让用户提供的 URL 经过任何允许 data: 方案的重定向链路。

内容安全策略(CSP)。默认情况下,严格的 CSP 会在 img-srcstyle-src 等指令中阻断 data URI。要想放行,必须在指令中显式包含 data:(例如 img-src 'self' data:)。要慎重——一旦放行 data URI,你就同时接受了页面选择内联的任意图片(或字体)。

日志与 PII。data URI 是 URL 的一部分。任何会捕获 URL 的日志或统计工具(服务端访问日志、浏览器历史、错误追踪平台)都会把整个负载也记录下来。如果你的 data URI 里包含用户头像、照片或截图,这些内容就会进入你的日志。不要把 PII 塞进你无法掌控的 URL 里。

// data: URI vs. blob: URL —— 该选哪个?

两者都能在不上传的前提下展示内存中的二进制数据,选择取决于这份数据需要存在于何处。

选择 data: URI 的场景:数据需要可以四处携带——嵌入 HTML、塞进 JSON、写入数据库、复制粘贴到邮件里。数据本身就是 URL。

选择 blob: URL 的场景:数据是本地的、生命周期短暂的——单页应用里的预览、触发下载、随页面关闭就消失的图片。URL.createObjectURL(blob) 给你一个短标识符(blob:https://example.com/12345-abcde),浏览器会把它映射回内存中的那个 Blob。比 data URI 短得多,而且用完后可以通过 URL.revokeObjectURL(url) 手动撤销。

经验法则:如果这个 URL 需要离开当前页面,用 data:;如果它只在页面内部活动,用 blob:。

// 常见调试问题

从 DevTools 复制出来的字符串被截断。当你从 Network 面板或 Elements 面板里复制一段较长的 data URI 时,浏览器经常会用省略号截断显示值。屏幕上看到的并不是完整的 URL。要拿到完整字符串,直接打开源文件(CSS、HTML、JSON),或者在控制台里用 document.querySelector('img').src——它会返回完整的 URL。

MIME 类型对不上。一份 PNG 负载被标成 data:image/jpeg;base64,...,在字节层面依然能解码——Base64 不在乎 MIME——但有些查看器会因这种不一致而拒绝渲染。真正的格式由魔数(PNG 的 iVBORw0KGgo)决定,所以拿不准时,把负载丢进我们的 Base64 图片解码器;它会从字节自动识别格式,这也是图片解码器最实用的功能之一。

少了那个逗号。正确格式是 data:image/png;base64,iVBORw...,而不是 data:image/png;base64;iVBORw...。把分号当分隔符或干脆漏掉分隔符,会让整个 URL 变成无效。

data: URI 里出现 URL-safe 风格的 Base64。标准的 data: URI 使用标准 Base64 字母表(包含 + 和 /)。如果你的负载是用 URL-safe 变体编码的(RFC 4648 §5,使用 - 和 _),嵌入前必须先转换回去——参见我们的Base64 URL-safe 与标准 Base64 对比

负载内部的空白字符。有些美化器会在 76 列处把长长的 Base64 串折行加上换行符。大多数浏览器在 <img src> 中能容忍这种格式,但少数(尤其是较老的 WebView)不行。嵌入前剥掉空白:str.replace(/\s+/g, '')

// 什么时候不要用 data: URI

体积超过 50 KB。缓存被破坏带来的下载成本,会盖过你节省的那次请求。
重复出现的图片。任何在多于一个页面里出现的资源,都应该走带缓存头的普通 URL。
面向公网的统计需求。跟踪像素、Beacon、基于像素的归因都无法工作,因为根本没有 HTTP 请求可以记录。
SPA 中展示的用户上传内容。请改用 URL.createObjectURL(blob)——它完全跳过 Base64 这一步,在内存里也大约比 data URI 小 4 倍。
处于不允许 data: 的严格 CSP 环境中。不要为了用一次 data URI 就在 CSP 里塞进 data:;先问清楚自己是不是真的非用不可。

// 30 秒速查表

格式:data:[mime-type][;base64],[payload]

最常见形式:data:image/png;base64,iVBORw0KGgo...

反向解码回图片:粘贴到我们的Base64 图片解码器(图像编码转换器)。

把图片编码成 data URI:使用我们的图片转 Base64 工具(图片编码转换器)——它直接给出可粘贴的完整 data: URI。

内联预算:小于 4 KB 一律内联,4–50 KB 视情况而定,大于 50 KB 用普通 URL。

浏览器 API:canvas.toDataURL()FileReader.readAsDataURL(),或者干脆自己拼字符串:'data:image/png;base64,' + btoa(binaryString)

延伸阅读:Base64 图片嵌入 · 在浏览器中预览 Base64 图片 · Base64 vs Base64URL vs Base32