必须在change事件中手动遍历input.files计算总大小,用array.from(files).reduce((s,f)=>s+f.size,0)累加,对空文件兜底校验;超限时清空input.value并拦截,因accept和max属性无效,且移动端需防重复绑定。

必须在 change 事件里读 input.files 累加 file.size 并立即拦截,不能等到提交表单才处理——用户已上传完才发现失败,上行带宽和连接就白耗了。
怎么准确计算总大小并阻止提交
浏览器不会自动汇总多文件总大小,得手动遍历 input.files。注意:files 是只读 FileList,但每个 file.size 是真实字节数,不是字符串长度。
- 用
Array.from(input.files).reduce((sum, f) => sum + f.size, 0)算总字节,别漏掉空文件(!file || !file.size要兜底) - 阈值建议设为略低于后端
post_max_size(比如后端是 50MB,前端拦 45MB),留出表单字段开销余量 - 触发拦截后必须清空
input.value = '',否则同一批超限文件重复选中不会再次触发change - 移动端(尤其微信内嵌 WebView)常因点击穿透或多次唤起选择框导致重复绑定,建议绑定后立刻解绑或用防抖
为什么 accept 和 max 属性完全没用
accept 只影响文件选择器的过滤提示,对大小零限制;HTML5 标准里根本没有 max 或 maxlength 这类属性能作用于 input[type="file"]。所有“大小限制”都得靠 JS 手动读 file.size 实现。
- 别信某些博客写的
<input max="10485760">—— 浏览器直接忽略,连 warning 都不抛 -
input.files.length是文件个数,file.size才是单个大小,二者相乘 ≠ 总大小(各文件大小不同) - 移动端 Safari 对
file.size读取是同步可靠的,不用 try/catch,但旧版 iOS WebView 可能返回 0,需加if (!file.size) return
后端已拦住,但用户还是卡在 pending 怎么办
这不是前端没拦好,而是中间层(Nginx/Apache/CDN/WAF)先截断了请求,根本没发到后端。典型表现是 Network 面板里请求状态卡在 pending 或直接返回 413 Request Entity Too Large。
- Nginx 必须配
client_max_body_size,且值 ≥ 后端post_max_size,否则前端再严也无意义 - PHP 场景下,若
$_FILES为空且无报错,大概率是post_max_size被超,查 PHP 错误日志搜POST Content-Length of XXXXX bytes exceeds the limit - Cloudflare 默认 100MB 请求体上限,企业版可调,免费版无法绕过,得走直传 OSS/S3
- 前端 fetch 上传时,
catch捕获的错误可能是网络中断、CORS 或 413,需检查error.name === 'TypeError' && error.message.includes('failed to fetch')再结合响应状态码区分
真正容易被忽略的是:前后端限制值没对齐,且中间层配置被遗忘。前端算总大小时漏掉隐藏字段(如 base64 编码的缩略图)、移动端反复触发导致同一组文件被 append 多次进 FormData,这些都会让实际请求体远超预期。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











