必须在drop事件中立即校验每个文件大小,超20MB即过滤并提示用户;禁止延迟至FormData构造阶段,避免内存警告或页面卡顿。

拖拽区域里怎么阻止超大文件进入上传流程
前端限制不是可选项,是必须做的第一道闸。用户拖进来一个 2GB 视频,你不拦,浏览器会照单全收,然后卡在 FileReader 或直接触发内存警告。关键不是“能不能传”,而是“要不要让它进处理队列”。
核心动作有两处:在 drop 事件里立刻检查每个 file.size,并配合视觉反馈让用户知道被拒了。别等 FormData 构造完再判断——那时页面可能已卡住。
- 用
file.size > 20 * 1024 * 1024判断是否超 20MB,别写20e6这种易错写法 - 对每个超限文件调用
alert或插入 DOM 提示,同时从待上传列表中过滤掉它 - 别只校验第一个文件:
Array.from(files).filter(f => f.size - 移动端 Safari 对刚拖入的
file.size读取有时延迟,加个setTimeout小延时再取值更稳
为什么 accept 属性和 input 的 maxlength 都没用
accept 只影响文件选择器弹窗里的筛选项,它不拦截拖拽行为;maxlength 对 <input type="file"> 完全无效——HTML 标准里压根没定义这个属性的作用对象是文件输入框。
你看到的“限制”只是表象:用户右键另存为一个 .exe 改后缀成 .jpg,照样能拖进来;或者直接用开发者工具删掉 JS 校验,input 元素本身不会报错也不会拒绝。
立即学习“前端免费学习笔记(深入)”;
-
accept="image/*"无法阻止用户拖入script.js,因为 MIME 类型由浏览器根据文件头或扩展名推测,不可信 - 真正有效的类型过滤只能靠
file.type.startsWith('image/')+ 后端二次解析文件头 - 所有 HTML 属性层面的“限制”都是装饰性的,仅作辅助提示
后端不设防,前端限制就等于没设
前端校验能提升体验,但绕过它只要禁用 JS 或改一行代码。后端才是最终守门人,而且必须在流式接收阶段就中断,不能等整个文件写完再检查大小。
常见服务端配置漏点:
- Nginx 默认
client_max_body_size是 1MB,拖一个 50MB 文件直接返回413 Request Entity Too Large - Express + multer 必须显式配
limits: { fileSize: 20 * 1024 * 1024 },否则超限文件静默丢弃,连错误都不抛 - Flask 的
MAX_CONTENT_LENGTH默认只有 512KB,不改就只能收小图,且错误响应是 400 而非 413,容易误判 - PHP 的
upload_max_filesize和post_max_size必须同时调大,后者要 ≥ 前者 + 表单其他字段开销
拖拽后页面跳转或自动下载,说明什么
这是最典型的 dragover 事件没处理的副作用。浏览器对图片、文本类文件有默认打开行为,如果你只监听了 drop 却没在 dragover 里调 e.preventDefault(),松手瞬间就会导航到该文件 URI。
调试时可以在 dragover 回调里打个 console.log('dragover'),拖进去没输出?那基本是事件没绑对目标元素,或者父容器用了 pointer-events: none 拦截了事件冒泡。
- 确保监听的是实际拖拽容器(比如
id="drop-area"的 div),不是document或body - 如果用了 Vue/React,确认 ref 拿到的是真实 DOM,虚拟节点上绑事件无效
- 多个嵌套容器时,检查是否有 CSS
z-index或transform导致事件捕获异常
拖拽上传的限制逻辑是分层的:前端做即时拦截和友好提示,Nginx 拦大流量,后端框架控单文件粒度,最后服务端代码做流式字节累计。少任何一层,都可能让异常文件穿过去。



















