文件上传:OSS 通行证与图片裁切

文件上传:OSS 通行证与图片裁切的一次完整理解

前端做文件上传时,很多人一开始会以为:

选择文件 -> 上传 -> 拿到一个链接 -> 页面直接显示

但实际业务里,尤其是接入 OSS、COS、VOD 这类对象存储或视频服务后,流程通常没有这么简单。更常见的是:

选择文件 -> 本地预览 -> 获取上传通行证 -> 直传 OSS -> 拿文件标识 -> 保存业务数据

这篇文章用通用示例梳理一下:文件上传、OSS 通行证、本地预览、图片裁切、访问鉴权之间到底是什么关系。

一、上传文件到底是为了什么

前端上传文件到 OSS,很多时候不是为了立刻拿到一个永久链接,而是为了拿到一个文件标识。

常见文件标识包括:

ossname
key
fileId

它们更像数据库里的“文件身份证”。

业务接口保存的通常不是一整段 base64,也不是浏览器临时地址,而是类似这样的字段:

avatar_abc123.png
course/cover/2026/07/03/abc123.png
vod-file-id-xxxx

之后页面详情再根据这些标识,返回真正可展示的 URL。

二、预览用的数据和保存用的数据不是一回事

前端要区分两类数据。

预览用:

base64
blob URL
http URL

保存用:

ossname
key
fileId

举个例子,用户新建一条内容并上传头像。

前端选择图片后,为了马上显示效果,可能会把图片转成:

data:image/png;base64,iVBORw0KGgo...

然后直接:

<img src="data:image/png;base64,iVBORw0KGgo..." />

这个可以显示,但它不是适合长期保存的数据。

真正提交业务接口时,前端更可能提交:

{
  "avatar": "avatar_abc123.png"
}

所以可以这样记:

预览是给用户看的
ossname/key 是给接口存的

三、base64、blob URL、http URL、ossname 的区别

1. base64

示例:

data:image/png;base64,iVBORw0KGgo...

特点:

图片内容直接编码在字符串中
可以直接作为 img src
常用于图片裁切后的预览
字符串比较长
可以转成 File 后上传

2. blob URL

示例:

blob:http://localhost:3000/5a1c2e...

特点:

浏览器为本地文件生成的临时地址
适合视频、PDF、原始文件本地预览
刷新页面或释放对象后会失效
不能当成长期地址保存到后端

3. http URL

示例:

https://cdn.example.com/image/avatar_abc123.png

特点:

线上资源地址
可以直接展示
是否能访问取决于权限、防盗链、签名和过期时间

4. ossname/key

示例:

avatar_abc123.png
image/avatar_abc123.png

特点:

是文件标识,不一定是完整 URL
适合保存到业务接口
通常需要后端转换成可访问 URL

四、为什么要先获取 OSS 通行证

前端不能随便往 OSS 传文件。

通常要先请求后端:

我要上传一个 png 文件,用途是头像,请给我上传参数

后端返回一套临时上传参数,可以理解成“上传通行证”。

常见字段:

host
key
ossname
policy
Signature
OSSAccessKeyId
expire

大致含义:

host:上传到哪里
key:文件在 OSS 里的完整路径
ossname:业务侧常用的文件名
policy:上传规则
Signature:签名,证明这次上传合法
OSSAccessKeyId:OSS 身份标识
expire:过期时间

接下来前端用 FormData 直传 OSS:

const form = new FormData()

form.append('OSSAccessKeyId', ossParams.OSSAccessKeyId)
form.append('policy', ossParams.policy)
form.append('Signature', ossParams.Signature)
form.append('key', ossParams.key)
form.append('success_action_status', 200)
form.append('file', file, ossParams.ossname)

await fetch(ossParams.host, {
  method: 'POST',
  body: form
})

这一步的重点是:

文件不是传给业务后端
而是浏览器直接传给 OSS

业务后端只负责发放临时上传参数。

五、FormData append 的第三个参数

很多人熟悉:

form.append('file', file)

但它也支持:

form.append('file', file, 'avatar_abc123.png')

第三个参数表示:

上传时这个文件在 multipart 表单里的 filename

它不是多加一个字段。

最终还是一个 file 字段,只是这个文件字段带了一个指定文件名。

六、图片裁切时发生了什么

图片裁切一般发生在前端本地。

常见流程:

用户选择图片
浏览器读取图片
裁切组件显示裁切框
用户确认裁切
canvas 生成裁切后的图片
转成 base64 或 Blob/File
页面立即预览
保存时再上传 OSS

裁切后常见代码思路:

const canvas = cropper.getCroppedCanvas()
const base64 = canvas.toDataURL('image/png')

这个 base64 可以直接预览:

<img src="data:image/png;base64,xxxx" />

也可以在上传前转成文件:

function base64ToFile(base64, filename) {
  const parts = base64.split(',')
  const mime = parts[0].match(/:(.*?);/)[1]
  const binary = atob(parts[1])
  const bytes = new Uint8Array(binary.length)

  for (let i = 0; i < binary.length; i++) {
    bytes[i] = binary.charCodeAt(i)
  }

  return new File([bytes], filename, { type: mime })
}

这里的关键点:

裁切确认不等于已经上传 OSS
本地能预览不等于已经保存成功

七、atob 和 btoa

这两个方法经常出现在 base64 处理里。

准确含义:

atob:Base64 字符串 -> 二进制字符串
btoa:二进制字符串 -> Base64 字符串

例如:

const binary = atob(base64Body)

这一步是把 base64 内容还原成二进制字符串,之后才能放进 Uint8Array,再生成 Blob/File

注意:btoa 的输入不是任意中文字符串,而是二进制字符串。直接对中文调用 btoa 可能会报错。

八、withCredentials: false

上传到 OSS 时,经常会看到:

withCredentials: false

它的意思是:

这次请求不要携带 cookie 等身份凭证

因为 OSS 上传不靠当前业务系统的登录 cookie 判断权限,而是靠:

policy
Signature
OSSAccessKeyId
key

所以直传 OSS 时通常不需要带登录态。

九、为什么视频 src 复制出来打不开

图片、视频、合同等资源不一定都是公开资源。

有些资源访问时需要:

Referer 防盗链
临时签名参数
token
auth_key
cookie
播放鉴权

所以可能出现:

页面里 video 能播放
复制 video src 到无痕模式打不开
加上后端给的鉴权参数后能打开
播放过一次后因为缓存又能打开

尤其是视频,可能还涉及分片:

index.m3u8
segment_001.ts
segment_002.ts
segment_003.ts

看起来 video 标签只有一个 src,但播放器实际会继续请求很多资源。

如果这些资源都需要鉴权,单独复制 src 打开就很容易失败。

更稳的设计是:

数据库长期保存 fileId/key/ossname
播放前请求后端接口
后端返回当前有效的播放 URL
前端使用这个 URL 播放
过期后重新获取

十、一个通用上传流程示例

1. 用户选择图片
2. 前端用 base64 或 blob URL 预览
3. 如果需要裁切,先在前端裁切
4. 点击保存
5. 前端请求后端获取 OSS 上传参数
6. 前端用 FormData 直传 OSS
7. OSS 上传成功
8. 前端拿 ossname/key
9. 前端调用业务保存接口
10. 后续详情接口返回可展示地址

十一、最容易混淆的点

本地预览成功,不代表文件已经上传成功
上传 OSS 成功,不代表业务数据已经保存成功
拿到 ossname,不代表拿到了永久公开访问链接
http 链接能不能访问,取决于权限、防盗链、签名和过期时间
blob URL 只能当前浏览器临时用
base64 可以预览,但不适合长期保存

十二、最后的记忆方式

base64/blob:前端预览体验
ossname/key:业务保存标识
签名 URL:当前时刻可访问的临时门票
详情接口:长期展示时的数据来源

一句话总结:

文件上传不是简单地“拿链接”,而是“本地预览、获取通行证、直传存储、保存标识、按需换取可访问地址”的完整链路。
posted @ 2026-07-03 18:45  jialiangzai  阅读(3)  评论(0)    收藏  举报