最简上传入口是<input type="file">,仅提供文件选择能力,需配合JS或表单提交实现上传;accept仅过滤界面显示,真实校验须用JS读取files[0].type或后缀名;multiple支持多选,files为FileList需转数组;webkitdirectory/directory可选文件夹但兼容性差且无目录结构;change事件中需判空;FormData+fetch上传时勿手动设Content-Type;后端收不到文件常见原因:Express缺multer、Flask误用request.form、Nginx client_max_body_size过小;大文件须进度条和分片上传,XHR支持onprogress,fetch不支持,分片需处理并发、重试、去重等复杂逻辑。

用 <input type="file"> 最简上传入口
浏览器原生支持文件上传,核心就是 <input type="file">。它不发请求,只提供选择文件的能力,后续必须配合 JavaScript 或表单提交才能真正上传。
常见错误是以为加了 accept 就能限制类型,其实它只是过滤文件选择器界面的显示项,用户仍可通过“所有文件”绕过。真正校验得靠 JS 读取 files[0].type 或后缀名。
-
multiple属性允许选多个文件,此时input.files是FileList,不是数组,要用Array.from()转换才能用map、filter -
webkitdirectory(Chrome/Safari)或directory(Firefox)可选整个文件夹,但注意:不是所有浏览器都支持,且返回的是扁平化的FileList,无目录结构 - 避免直接绑定
change后立刻读取input.files——如果用户取消选择,files.length为 0,但事件仍会触发
用 FormData + fetch 发送二进制数据
现代上传基本不用表单提交(method="POST" enctype="multipart/form-data"),而是用 FormData 构造请求体,搭配 fetch 或 XMLHttpRequest 控制更细。
关键点在于:不要手动设置 Content-Type 头。一旦设了(比如 "multipart/form-data"),浏览器就无法自动插入 boundary,导致后端解析失败。让 fetch 自己处理。
立即学习“前端免费学习笔记(深入)”;
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
- 添加文件:
formData.append("file", input.files[0]);若字段名需动态,变量名必须用字符串字面量,不能写成formData.append(fieldName, ...)然后指望后端按变量名接收 - 可同时 append 文本字段:
formData.append("desc", "report-v2"),后端收到的就是同个请求里的 multipart 字段 - 大文件上传建议加
AbortController,否则用户点了取消,请求还在后台跑
后端接收不到文件?先查这三处
前端看着正常,但后端收不到 file 字段,大概率卡在这几个地方:
- Node.js(Express)没配
multer或busboy中间件——默认不解析multipart/form-data,req.body和req.file都是空的 - Python Flask 用了
request.form读文件——错,文件在request.files里,form只存文本字段 - Nginx 默认限制上传大小(
client_max_body_size 1m),超限会直接返回 413,连后端都进不去;要改配置并重载
进度条和分片上传不是“锦上添花”,是刚需
用户选个 500MB 视频,等 2 分钟没反应,大概率会刷新页面。单纯靠 fetch().then() 不知道传到哪了。
用 XMLHttpRequest.upload.onprogress 能拿到已上传字节数,但注意:它不适用于 fetch(目前无标准替代)。真要进度反馈,要么切回 XHR,要么用第三方库如 axios(它封装了 onUploadProgress)。
断点续传、秒传、大文件稳定上传,靠的是分片:前端把文件切块(如每块 5MB),按顺序上传,后端合并。这时候文件名、分片序号、总片数都得作为字段传过去,否则后端不知道怎么拼。
别低估分片逻辑的复杂度——MD5 计算阻塞主线程、并发控制、失败重试、已上传分片去重,这些都不是加几行 slice() 就能搞定的。

















