HTML文件上传控件完整教程:accept、multiple与前端预览实现

文件上传是表单里非常常见的功能,比如头像上传、身份证图片提交、附件上传、相册选择、简历投递等。HTML 原生的 input type="file" 已经提供了基础能力,再配合 acceptmultiple 和少量 JavaScript,就能完成大多数前端交互。

不过文件上传也容易踩坑:前端限制不等于安全校验,图片预览不等于已经上传成功,多文件选择也不等于后端一定能接收。本文从基础控件讲起,介绍文件类型限制、多文件上传、前端预览和安全注意事项。

基础控件

最基础的文件上传控件写法很简单,只需要把输入框类型设置为 file。如果表单要直接提交文件,通常还需要设置 method="post"enctype="multipart/form-data"

<form action="/upload" method="post" enctype="multipart/form-data">
  <label for="avatar">上传头像</label>
  <input id="avatar" name="avatar" type="file">
  <button type="submit">提交</button>
</form>

enctype="multipart/form-data" 是传统表单上传文件时的重要配置。如果少了它,后端可能收不到文件内容。使用 Ajax 和 FormData 上传时,也要确保请求体按文件表单方式发送。

accept 限制类型

accept 用来提示浏览器允许用户选择哪些类型的文件。比如只允许选择图片,可以写成 accept="image/*";只允许 PDF,可以写成 accept="application/pdf"

<input type="file" accept="image/*">
<input type="file" accept=".pdf,.doc,.docx">

accept 只是前端选择提示,不是安全边界。用户仍然可能通过修改文件扩展名、拖拽、接口请求等方式绕过限制。因此后端必须重新检查文件类型、大小和内容。

HTML文件上传控件与前端预览示意图
文件上传前端负责提升体验,真正的安全校验必须在后端完成。

multiple 多文件

如果希望用户一次选择多个文件,可以添加 multiple 属性。浏览器会允许用户多选,JavaScript 中可以通过 files 列表读取所有文件。

<input id="photos" name="photos" type="file" accept="image/*" multiple>

多文件上传时,前端最好给出数量限制和大小提示。比如最多选择 9 张图片、单张不超过 5 MB。即使前端做了限制,后端也要再次校验,避免用户绕过页面直接提交超大文件。

读取 File 对象

文件控件的 files 属性会返回一个类数组对象,每一项都是 File。它包含文件名、大小、类型、最后修改时间等信息。

const input = document.querySelector('#photos');

input.addEventListener('change', () => {
  const files = Array.from(input.files);
  files.forEach((file) => {
    console.log(file.name, file.size, file.type);
  });
});

file.size 的单位是字节,显示给用户时通常需要转换成 KB 或 MB。file.type 是浏览器识别出的 MIME 类型,但它也不能作为唯一安全依据。

图片预览

图片上传前,常见需求是先在页面上显示预览。可以使用 URL.createObjectURL() 为本地文件生成临时地址,再把它赋给图片的 src

<input id="avatar" type="file" accept="image/*">
<img id="preview" alt="图片预览" width="160">
const avatar = document.querySelector('#avatar');
const preview = document.querySelector('#preview');

avatar.addEventListener('change', () => {
  const file = avatar.files[0];
  if (!file) return;

  preview.src = URL.createObjectURL(file);
});

这种方式适合预览图片,不需要先上传到服务器。对于大图或频繁切换的预览,使用完临时地址后可以调用 URL.revokeObjectURL() 释放资源。

前端大小校验

为了避免用户选择过大的文件,可以在前端先做一次大小判断。这样能减少无效上传,也能更快给用户反馈。

const maxSize = 5 * 1024 * 1024;

if (file.size > maxSize) {
  alert('文件不能超过 5MB');
}

前端大小校验主要是体验优化。真正的上传限制仍然要由后端、Web 服务器和应用配置共同控制,比如 Nginx 的请求体大小限制、PHP 或 Node.js 的上传大小限制等。

使用 FormData 上传

如果不想使用传统表单提交,可以用 FormData 结合 fetch 上传文件。不要手动设置错误的 Content-Type,浏览器会自动生成带边界的 multipart 请求头。

const formData = new FormData();
formData.append('avatar', file);

fetch('/upload', {
  method: 'POST',
  body: formData
});

如果是多文件,可以循环追加,字段名根据后端约定决定。有些后端喜欢 photos[],有些后端使用同名字段多次追加,前后端要提前约定清楚。

拖拽上传

拖拽上传本质上也是读取文件对象。用户把文件拖到指定区域后,可以从拖拽事件里拿到 dataTransfer.files

dropArea.addEventListener('drop', (event) => {
  event.preventDefault();
  const files = Array.from(event.dataTransfer.files);
  console.log(files);
});

拖拽上传体验更好,但也要处理拖入、拖出、释放、错误提示等状态。如果只是简单表单,不一定需要一开始就做拖拽交互,原生文件控件已经足够。

安全注意事项

文件上传是高风险入口。后端必须限制文件大小、扩展名、MIME 类型、真实文件内容,并且不要把用户上传文件直接放到可执行目录。图片也应重新处理或转存,避免伪装文件和恶意内容。

文件名也不能直接信任。用户上传的原始文件名可能包含特殊字符、路径片段或重复名称。更稳妥的做法是在后端生成新的文件名,并把原始文件名只作为展示信息保存。

实践建议

一个稳妥的上传流程通常是:前端用 accept 限制选择范围,用 multiple 控制是否允许多选,用 JavaScript 做大小和数量提示,用预览提升体验;后端重新校验类型、大小和权限,生成安全文件名,存储到合适位置。

不要把前端校验当成安全措施,也不要为了炫技把上传控件做得过重。先保证文件选择、预览、错误提示和后端校验闭环,再根据业务需要增加拖拽、进度条、断点续传等高级能力。

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容