前端图片二进制、文件流、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 根本拿不到网络原始二进制!
流程:
- 浏览器加载图片渲染画面
- 重新绘制一帧画面到画布
- 重新编码生成全新图片二进制
本质
对着屏幕截图,不是原图文件
缺点
- ❌ 画质损耗
- ❌ 丢失原图元数据
- ❌ 强制格式转换
四、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
六、二进制传输铁律(你之前不知道)
- JSON 绝对不能直接放原始二进制
- 会乱码、损坏数据
- 二进制只有两条合法出路
- 单独接口返回文件流(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是原图二进制
答案:错
解析
是重新渲染编码的新图片,非原图
八、最终四大终极对比表(背诵)
九、最终一句话通关总结(全部知识浓缩)
- 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生成)