Skip to content

上传校验

上传校验的核心不是“能不能传”,而是“是否应该让这个文件进入上传流程”。

为什么上传前就要校验

越早拦截,成本越低。

常见原因包括:

  • 文件太大
  • 文件类型不符合要求
  • 图片尺寸或比例不符合要求
  • 一次选择的文件数量超限

这些问题如果等到请求发出去才处理,用户体验通常会更差。

最常见的几类校验

上传前最常做的通常是:

  • 大小校验
  • 类型校验
  • 数量校验
  • 图片尺寸 / 比例校验

文件大小校验

直接看 file.size

js
const maxSize = 5 * 1024 * 1024

if (file.size > maxSize) {
  throw new Error('文件大小不能超过 5MB')
}

这是最基础也最常见的一层。

文件类型校验

先看 file.type

js
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif']

if (!allowedTypes.includes(file.type)) {
  throw new Error('文件类型不支持')
}

这层成本低,适合先做快速筛选。

也可以看扩展名

js
const ext = file.name.split('.').pop()?.toLowerCase()
const allowedExtensions = ['jpg', 'jpeg', 'png', 'gif']

if (!allowedExtensions.includes(ext)) {
  throw new Error('文件扩展名不支持')
}

但扩展名只能作为弱校验,因为文件名可以伪造。

更严格时看文件头

如果需要更可靠的类型判断,可以读取文件前几个字节做魔数校验:

js
const signatures = {
  'image/jpeg': [0xff, 0xd8, 0xff],
  'image/png': [0x89, 0x50, 0x4e, 0x47],
}

这比只看文件名更稳,但前端校验本身仍然不是最终安全边界,服务端还要再验一次。

文件数量校验

多文件上传时,不要只校验单个文件,也要校验总数:

js
const files = Array.from(fileInput.files)

if (files.length > 5) {
  throw new Error('最多只能上传 5 个文件')
}

图片尺寸和比例校验

图片类上传常会进一步校验:

  • 宽高
  • 长宽比

通常会先把文件转成临时 URL,再用 Image 读取:

js
const url = URL.createObjectURL(file)
const img = new Image()

img.onload = () => {
  console.log(img.width, img.height)
  URL.revokeObjectURL(url)
}

img.src = url

比例校验

js
const ratio = img.width / img.height
const target = 16 / 9

if (Math.abs(ratio - target) > 0.1) {
  throw new Error('图片比例不符合要求')
}

尺寸校验

js
if (img.width < 800 || img.height < 600) {
  throw new Error('图片尺寸过小')
}

一个容易误解的点

前端上传校验更多是:

  • 提前拦截
  • 提升体验
  • 减少无效请求

它不是最终安全校验。

真正影响系统安全和数据可信度的规则,服务端必须再执行一次。

使用建议

  • 先做低成本校验,例如数量、大小、file.type
  • 图片类资源再补尺寸和比例校验。
  • 规则严格时,可增加魔数校验,但不要把它当最终防线。
  • 上传校验始终要有服务端兜底。

基于 MIT 许可发布