fileinput 元素仅用于本地文件选择,不自动上传;需配合 form(enctype="multipart/form-data")提交,或用 JavaScript 读取 files 构造 FormData 并 fetch 上传,且须校验类型、大小,服务端字段名与 Nginx 配置须匹配。
form 和 submit 或 JavaScript 手动提交很多人以为 点选文件后就自动上传了,其实它只是本地文件选择控件,不触发任何网络请求。真正上传需要:
– 封装在 中并提交;
– 或用 JavaScript 读取 input.files[0],构造 FormData,再用 fetch 或 XMLHttpRequest 发送。
enctype="multipart/form-data"
如果漏掉这个属性,服务端收不到文件字段,request.files(如 Flask)或 $_FILES(PHP)会为空,且浏览器可能静默降级为 application/x-www-form-urlencoded,只传文件名不传内容。
FormData,且不能用 JSON.stringify
FormData 是二进制友好的容器,直接 append 文件对象即可;若错误地把 FormData 转成 JSON(比如 JSON.stringify(new FormData())),会得到空对象或报错,因为 FormData 不可序列化。
formData.append("file", input.files[0])
JSON.stringify(formData) 或 fetch(url, { body: formData }) 却没设 headers(其实不用设,fetch 会自动设置正确 Content-Type,但手动设反而容易出错)const input = document.querySelector('input[type="file"]');
input.addEventListener('change', () => {
const file = input.files[0];
if (!file) return;
const formData = new FormData();
formData.append('document', file); // 字段名要和服务端约定一致
fetch('/api/upload', {
method: 'POST',
body: formData // 不要加 headers,让浏览器自动设 multipart boundary
});
});
input[type="file"] 不提供内置上传管理HTML 原生 input 只负责选文件,后续所有事——比如预览图片、限制 .pdf、拦截超 5MB 的文件、显示进度条、处理失败重试——都得手写 JS 实现。框架(如 Dropzone、Element Plus 的 el-upload)只是封装了这些重复逻辑。
accept="image/png,image/jpeg" 是提示,必须在 JS 中用 file.type 或 file.name.split('.').pop() 二次校验file.size > 5 * 1024 * 1024,否则上传中途可能被 Nginx 或后端截断,返回 413 后遍历 input.files,逐个 append 到 FormData
,或打包成数组字段实际开发中,最常被忽略的是服务端接收逻辑是否匹配前端字段名,以及 Nginx 是否配置了 client_max_body_size。这两处一错,前端看似发出去了,后端却收不到文件。