日记:2026/08/28

·10 min read·

前端图片二进制、文件流、Base64、Blob、CORS 终极通关笔记(全覆盖易错点)

前端图片二进制、文件流、Base64、Blob、CORS 终极通关笔记(全覆盖易错点)

前端图片二进制、文件流、Base64、Blob、CORS 终极通关笔记

前言

本文汇总 所有你曾经混淆、答错、理解模糊 的知识点,结合代码、原理、对比、踩坑点,全覆盖本次对话所有内容,无遗漏。

一、核心四大终极概念(你之前最混乱的)

1. ReadableStream 文件流(水管)

核心定义(重点记忆)

  • 流 = 分段传输的二进制管道
  • 不存储完整数据,一块一块 chunk 流式吐出
  • 一次性消费:读完即销毁,不可重复读

通俗理解

  • ReadableStream:水管
  • 二进制 chunk:每一滴水
  • Blob:接满水的水桶

关键特性(易错点✅你曾经不懂)

  • 流只能消费一次(blob() / arrayBuffer() 后作废)
  • 适合大文件、边下载边解析
  • res.body 就是原生图片文件流

2. Blob 二进制容器(水桶)

核心定义

  • Blob = 浏览器内存中 完整、不可变的二进制数据包
  • 存放完整原图二进制
  • 可以反复读取、多次转换
  • 所有前端二进制操作的中间万能载体

支持转换

  • Blob → blobURL
  • Blob → Base64
  • Blob → File
  • Blob → ArrayBuffer

3. Base64 / DataURL

核心

  • 编码,不是加密
  • 二进制转文本,体积膨胀 33%
  • 可以存入数据库、JSON、本地存储

格式

data:image/png;base64,xxxxxxxx

4. 三种 URL 终极区分(你错题最多的板块)

1)HTTP 真实 URL

  • https://cdn/xxx.png
  • 走网络请求
  • 永久有效
  • 可存数据库
  • JS读取二进制受 CORS 限制

2)Blob 伪 URL(你答错的原题)

  • blob:https://xxx/xxxx
  • 不走网络
  • 指向浏览器当前页面内存
  • 页面刷新/关闭立即失效
  • ❌ 绝对不能存数据库、localStorage

3)Base64 DataURL

  • 不走网络
  • 文本存储,永久保存
  • 体积大

二、CORS 终极真相(你最大的知识盲区)

必考真理(90%前端搞混)

  • ✅ 浏览器底层正常下载完整二进制文件流
  • ✅ 正常渲染图片
  • ❌ JS 无法获取这一份二进制
  • ❌ 不受 CORS 限制

2. fetch / ajax

想要 JS 拿到二进制、流、Blob、Base64

  • ✅ 必须服务器开 CORS

两种跨域模式深坑(你之前完全不懂)

模式1:mode: "cors"(默认)

  • 无CORS头 → 直接报错,拿不到响应

模式2:mode: "no-cors"(超级大坑)

  • 网络状态200,图片下载成功
  • ❌ res.body = null
  • ❌ JS 拿不到任何二进制
  • 浏览器:允许你发请求,屏蔽所有响应体数据

三、两种图片转 Base64 方案(核心考点)

方案1:Fetch + Blob + FileReader(CORS开启✅无损原图)

原理

读取服务器原始二进制流,无损转换

完整可运行代码

async function urlToBase64(url) {
  const res = await fetch(url, {
    mode: "cors"
  });
  const blob = await res.blob();
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.readAsDataURL(blob);
    reader.onload = () => resolve(reader.result);
  });
}

优点

  • ✅ 无损原图
  • ✅ 保留透明通道、原图格式、EXIF信息

缺点

  • 必须 CORS

方案2:Image + Canvas(CORS关闭✅妥协方案)

【重点纠正你曾经的误区】

  • ❌ 错误理解:Canvas 拿到网络原始二进制
  • ✅ 正确真相(你最核心的知识补全):Canvas 根本拿不到网络原始二进制!

流程:

  1. 浏览器加载图片渲染画面
  2. 重新绘制一帧画面到画布
  3. 重新编码生成全新图片二进制

本质

对着屏幕截图,不是原图文件

缺点

  • ❌ 画质损耗
  • ❌ 丢失原图元数据
  • ❌ 强制格式转换

四、ReadableStream、Blob、BlobURL 转换链路(必背)

完整数据流

HTTP响应
→ ReadableStream(分段流、一次性)
→ 全部消费 → Blob(完整二进制)
→ URL.createObjectURL() → blob伪URL

流转 BlobURL 完整代码

async function streamToBlobUrl(url) {
  const res = await fetch(url, { mode: "cors" });
  // 原生文件流
  const stream = res.body;
  // 流转完整二进制
  const blob = await res.blob();
  // 生成内存临时地址
  const blobUrl = URL.createObjectURL(blob);
  return { stream, blob, blobUrl };
}
// 用完必须释放!防止内存泄漏
// URL.revokeObjectURL(blobUrl)

关键规则

  • Stream 只能读一次
  • Blob 可以无限次复用
  • BlobURL 页面销毁即失效

五、数据库存储方案终极对比(你曾经混淆)

1. 数据库存 HTTP URL(生产95%场景)

优点

  • 数据库轻量、查询快、备份快
  • 支持 CDN、浏览器缓存

缺点

  • 图片文件删除后出现 脏数据、死链接

2. 数据库存 BLOB 二进制(不推荐)

致命缺点

  • 数据库爆炸、备份超大、查询慢
  • 无法CDN加速
  • 业务绝对禁止存大图

3. 后端返回文件流

最重要纠正你的错题

  • ❌ 错误认知:后端返回文件流 = 数据库存了BLOB
  • ✅ 正确:文件流是 HTTP 响应形式,和数据库存储无关!

流来源可以是:

  • 磁盘文件
  • OSS对象存储
  • 数据库BLOB

六、二进制传输铁律(你之前不知道)

  1. JSON 绝对不能直接放原始二进制
    • 会乱码、损坏数据
  2. 二进制只有两条合法出路
    • 单独接口返回文件流(Content-Type: image/png)
    • Base64 转文本塞进JSON

七、你之前做错的题目 + 精准错题复盘

错题1

blob:https://xxx 可以存数据库、跨页面使用

答案:错

解析

blobURL 绑定当前页面内存,刷新即报废,只是临时指针

错题2

后端返回文件流,说明数据库一定存了BLOB

答案:错

解析

流是输出方式,BLOB是存储方式,无关

错题3

图片能img显示 = fetch一定能拿到二进制

答案:错

解析

img不受CORS,JS fetch受CORS限制

错题4

mode:no-cors 可以拿到二进制

答案:错

解析

res.body = null,完全屏蔽数据

错题5

Canvas导出的Base64是原图二进制

答案:错

解析

是重新渲染编码的新图片,非原图

八、最终四大终极对比表(背诵)

类型走网络可存数据库可跨页面体积
HTTP URL最小
BlobURL无膨胀
Base64+33%
对象是否完整二进制是否可重复读取
ReadableStream❌分段❌一次性
Blob✅完整✅无限复用

九、最终一句话通关总结(全部知识浓缩)

  • img能显示 ≠ JS能拿二进制
  • CORS只限制JS读取,不限制浏览器渲染
  • Stream是管道、Blob是完整水、Base64是文本包装
  • BlobURL临时内存用、Base64持久化用、HTTP URL生产最优
  • Canvas是截图、Fetch是原图
  • 返回流 ≠ 数据库存二进制

十、面试高频绝杀问答(你已全部吃透)

为什么图片能显示但fetch跨域?

img不受CORS,JS读取二进制受浏览器安全限制

no-cors为什么200却拿不到数据?

浏览器返回不透明响应,body置空,屏蔽二进制

BlobURL为什么不能存数据库?

依赖当前页面内存,生命周期极短

Canvas和Fetch转Base64区别?

Fetch:无损原图;Canvas:重绘新图、有损

生产图片到底存URL还是二进制?

一律存CDN URL,禁止数据库存大图BLOB

(豆包AI生成)

Twitter