javascript如何实现文件上传功能【教程】

最稳妥的浏览器原生文件上传方式是使用 FormData,它自动处理 boundary 和 multipart/form-data 头;切忌手动设置 Content-Type 或 JSON.stringify 文件,大文件需用 XMLHttpRequest 监听进度或分片上传,并确保前后端字段名、中间件配置及 Nginx 限制等细节一致。

FormData 构造上传数据最稳妥

浏览器原生上传不依赖第三方库,核心就是 FormData。它能自动处理文件字段的边界(boundary)、编码和 multipart/form-data 头,比手动拼接字符串或设置 Content-Type 可靠得多。

常见错误是直接把 File 对象 JSON.stringify 后发请求——这会失败,因为二进制内容无法被 JSON 序列化。

  • 获取 files[0] 后,直接 appendFormData 实例里
  • 字段名必须和后端约定一致,比如后端期待 file 字段,就写 formData.append('file', file)
  • 如需额外参数(如用户 ID、分类),也用 append 加入,不用单独塞进 body 或 query

fetch 上传时别设 Content-Type

fetch 发送 FormData 时,**绝对不要手动设置 headers: {'Content-Type': 'multipart/form-data'}**。浏览器会自动添加带随机 boundary 的正确头;手动设了反而会导致 boundary 缺失,后端解析失败,典型报错是 Unexpected end of multipart data 或空文件。

正确写法只传 body

fetch('/upload', {
  method: 'POST',
  body: formData // 不要加 headers
})

大文件上传要考虑 onprogress 和分片

单次传几百 MB 文件容易超时、卡死或被代理截断。纯前端可控的底线方案是监听 XMLHttpRequest.upload.onprogressfetch 目前无标准进度事件):

  • 必须用 XMLHttpRequest 而非 fetch 才能拿到实时上传进度
  • 分片上传需后端配合:前端切块、按序号上传、后端合并。前端切片用 file.slice(start, end),注意 Blob 方法在 Safari 中对 large file 支持不稳定
  • 上传中断续传需服务

    端记录已接收块,前端校验 MD5 或 SHA-1(计算大文件哈希会阻塞主线程,要用 Web Worker

后端接收不到文件?先查 req.headers['content-type']

前端看似发成功,但 Node.js(Express/Koa)、Python(Flask/Django)等后端收不到 req.filerequest.files,大概率是 content-type 不匹配或中间件未启用。

  • Express 需显式加 multerbusboy 解析 multipart;仅 app.use(express.json()) 不管用
  • 检查 Node.js 日志里 req.headers['content-type'] 是否以 multipart/form-data; boundary=... 开头,如果不是,说明前端误设了 header 或用了错误 body 格式
  • Nginx 默认限制上传大小为 1MB,超限会返回 413,需调 client_max_body_size
真正卡住的地方往往不是怎么发,而是前后端对“文件字段名”“是否多文件”“是否带 token 在 header”这些细节没对齐。传之前用浏览器 Network 面板点开请求,看 Payload 和 Headers 是最直接的验证方式。