javascript如何实现文件上传?_掌握javascript文件操作API【教程】

14次阅读

浏览器中无法直接读取文件系统路径,必须通过用户主动选择(如)获取 File 对象,再用 FileReader 读取内容;上传需用 FormData 包裹 File 对象发送,不可 JSON.stringify;多文件、分片、校验等均需前后端协同。

javascript 如何实现文件上传?_掌握 javascript 文件操作 API【教程】

怎么用 File 对象读取本地文件内容

浏览器 中无法直接读取文件系统路径,必须通过用户主动选择(如 )触发,才能拿到 File 实例。这个对象是 Blob 的子类,自带 namesizetype 等属性,但内容需用 FileReader 解析。

常见错误是试图直接 console.log(file) 就以为能看见内容——其实只能看到元信息;真正读内容要调用 readAsText()readAsDataURL()readAsArrayBuffer()

  • 读文本文件(如 .txt、.json):用 readAsText(file, 'UTF-8'),注意 编码 参数不传可能乱码
  • 读图片预览:用 readAsDataURL(file),结果是 base64 字符串,可直接赋给 javascript 如何实现文件上传?_掌握 javascript 文件操作 API【教程】
  • 大文件慎用 readAsDataURL,内存暴涨且无法中断;优先考虑分块读取或直接上传

怎么把文件发给 后端(不刷新页面)

核心是用 FormData 包裹 File 对象,再通过 fetchXMLHttpRequest 发送。后端收到的是 multipart/form-data,和表单提交行为一致。

关键点在于:不能把 File 直接 JSON.stringify 后发过去——它不是普通 JS 对象,序列化后只剩空对象;也不能手动拼 URL 查询参数上传文件。

立即学习Java 免费学习笔记(深入)”;

  • const fd = new FormData(); fd.append('upload', file); —— 第二个参数必须是 FileBlob,不能是路径字符串
  • 如果需要额外字段(如用户 ID),用 fd.append('uid', '123'),后端会一并收到
  • fetch('/api/upload', { method: 'POST', body: fd}) 即可;注意不要设 Content-Type 头,浏览器会自动设置 boundary
  • 若用 XMLHttpRequest,记得监听 upload.onprogress 做进度条,fetch 原生不支持上传进度

input[type="file"] 的多文件、限制与事件陷阱

默认单选,加 multipile 属性(注意拼写是 multipile 不是 multiple?错,是 multiple)才支持多选;但用户仍可按住 Ctrl/Command 点击多个,或拖拽多个文件到区域——前提是绑定的元素支持 dragoverdrop 事件。

容易忽略的是:每次选择新文件,input.files 是全新对象,不会和上次合并;清空它不能靠 value = ''(部分浏览器不生效),得用 input.value = null

  • 限制类型:accept="image/*,.pdf" 仅过滤文件选择器界面,不防伪造;服务端必须二次校验 file.type 和实际二进制头
  • 限制大小:前端 可用 if (file.size> 5 * 1024 * 1024) {……} 提前提示,但不能替代后端校验
  • change 事件只在用户选择后触发一次;若想响应拖放,需监听 drop 并从 event.dataTransfer.filesFileList

大文件分片上传为什么不能只靠前端控制

分片本身很简单:用 file.slice(start, end) 得到 Blob,再逐个发给后端。难点在服务端配合——必须能接收分片、暂存、校验顺序、合并,还要处理断点续传(比如记录已上传的 chunk hash)。

前端只做切片和重试逻辑,没服务端支撑就是半截功能。常见错误是认为“前端分了片就等于上传可靠”,结果网络中断后整个流程卡死。

  • file.slice() 返回新 Blob,不是引用;切片大小建议 1–5 MB,太小 HTTP 开销大,太大内存压力高
  • 每个分片应带唯一标识(如文件名 + index + hash),方便后端去重和排序
  • 上传完成前,别删掉原始 File 对象——万一要重试某一片,还得再 slice 一次
  • 移动端对 slice() 兼容性没问题,但 iOS Safari 对超大 Filesize 读取偶尔不准,建议用 file.arrayBuffer().then(buf => buf.byteLength) 校验

文件上传看着简单,真正上线时最常翻车的不是语法,而是对 File 生命周期、HTTP 协议边界、以及前后端职责划分的理解偏差。

text=ZqhQzanResources