使用AJAX实现文件上传|详细教程与核心问题解决技巧

文章目录CloseOpen

    • AJAX上传文件的基础逻辑:从FormData到请求发送
    • AJAX上传最容易踩的3个坑,我帮你踩过了
      • 坑1:进度条做不出来?其实是没监听对事件
      • 坑2:大文件上传卡顿?试试分片上传
      • 坑3:跨域报错?不是AJAX的问题,是后端没配置CORS
      • FormData在老浏览器里能用吗?
      • AJAX上传能同时传多个文件吗?
      • 为什么进度条没反应?
      • 跨域报错是AJAX代码的问题吗?
      • 多大的文件需要用分片上传?

    AJAX上传文件的基础逻辑:从FormData到请求发送

    其实AJAX上传文件的核心就一个“小工具”——FormData。你可以把它理解成一个“虚拟的表单”,既能装文件,也能装文字信息(比如文件名、分类),而且浏览器会自动帮你把这些内容转换成服务器能认的“multipart/form-data”格式——不用你自己拼复杂的字符串,省了超多麻烦。

    我第一次用的时候,还傻兮兮地手动构造请求体:把文件转成Base64字符串,再拼到JSON里发出去,结果后端根本解析不了。后来查了MDN才知道,FormData是浏览器专门为“上传文件”设计的——它能完美模拟传统表单的提交方式,但又不会刷新页面。

    具体怎么做呢?我拆成5步,你跟着走肯定没错:

  • 拿到用户选的文件:先放一个标签,然后用JS监听它的change事件——当用户选好文件,e.target.files[0]就是你要的文件对象(比如头像、商品图)。
  • 创建FormData并加文件let formData = new FormData();然后用formData.append('file', file)把文件加进去——要是你还想传点其他信息(比如“这是商品图”),可以再加一句formData.append('type', 'product_img'),特别方便。
  • 初始化XHR对象let xhr = new XMLHttpRequest();——这是AJAX的“核心引擎”,负责发请求和收响应。
  • 设置请求参数xhr.open('POST', '/api/upload', true);——这里要注意3点:①方法必须是POSTGET有长度限制,传不了大文件);②/api/upload是你后端的上传接口地址;③第三个参数true表示异步请求(不阻塞页面)。
  • 发送请求并监听结果xhr.send(formData);之后要加两个事件监听:xhr.onload(请求成功完成时触发)和xhr.onerror(请求失败时触发)。比如:
 xhr.onload = function() {

if (xhr.status === 200) {

alert('上传成功!');

// 这里可以更新页面,比如显示上传的图片

}

};

xhr.onerror = function() {

alert('上传失败,再试一次吧~');

};

为什么说这个逻辑“基础但关键”?因为我见过很多新手绕开FormData,用

FileReader读文件成Base64再传——不是不行,但Base64会比原文件大30%,传大文件的时候更卡;而且FormData能同时传文件和其他字段,比Base64灵活多了。比如我朋友的博客头像上传,一开始用Base64,1MB的头像传要2秒,换成FormData后只要1秒不到,还稳定。

AJAX上传最容易踩的3个坑,我帮你踩过了

基础逻辑学会了,但实际做的时候,你肯定会遇到一些“奇奇怪怪”的问题——我帮不同客户做过5次AJAX上传功能,踩了3个最常见的坑,今天一次性告诉你怎么避。

坑1:进度条做不出来?其实是没监听对事件

我之前帮电商客户做商品图上传时,明明加了进度条代码,但进度条就是不动。查了3小时才发现:进度事件要绑在

xhr.upload上,不是xhr本身!

正常的进度监听应该这么写:

js

xhr.upload.onprogress = function(e) {

if (e.lengthComputable) { // 判断是否能获取进度

let percent = (e.loaded / e.total) 100; // 计算百分比

document.getElementById(‘progressBar’).style.width = percent + ‘%’; // 更新进度条

}

};

为什么?因为

xhr本身的progress事件是监听“下载进度”(比如后端返回数据的进度),而xhr.uploadprogress才是“上传进度”——我之前就是绑错了地方,所以进度条没反应。后来改绑到upload上,进度条一下子就动了,客户还夸这个功能“很专业”。

坑2:大文件上传卡顿?试试分片上传

上个月帮做短视频的客户做上传功能,1GB的视频直接传,要么超时,要么传到一半断开。后来我想起之前学过的分片上传——把大文件切成一小块一小块的,分多次发给后端,后端再拼起来。

具体怎么做?核心是

File.slice()方法——它能把文件切成指定范围的“分片”。比如把1GB的文件切成100MB一块:

  • 计算分片参数
  • const chunkSize = 100 1024 1024; // 100MB每片const totalChunks = Math.ceil(file.size / chunkSize); // 总片数

  • 循环发送分片:用
  • for循环遍历每一片,用file.slice(i chunkSize, (i + 1) chunkSize)切出分片,然后把分片、分片序号、总片数一起发给后端:

    js

    for (let i = 0; i < totalChunks; i++) {

    let chunk = file.slice(i

    chunkSize, (i + 1) chunkSize);

    let formData = new FormData();

    formData.append(‘chunk’, chunk);

    formData.append(‘chunkIndex’, i);

    formData.append(‘totalChunks’, totalChunks);

    formData.append(‘fileName’, file.name);

    // 发送这个formData给后端

    sendChunk(formData); // 这里需要写一个发送分片的函数

    }

  • 后端合并分片:后端收到所有分片后,按chunkIndex的顺序把分片拼起来,就能得到完整的文件。
  • 这样做的好处是稳定——就算某一片传失败了,只需要重新传那一片,不用整个文件重传;而且后端处理小文件也更轻松。那个短视频客户用了分片上传后,1GB的视频上传成功率从50%升到了95%,老板还加了我微信说“下次有需求找你”。

    坑3:跨域报错?不是AJAX的问题,是后端没配置CORS

    我上个月做前端项目时,和后端联调上传功能,老是报“Access-Control-Allow-Origin”错误。我一开始以为是AJAX写得有问题,查了好几遍代码——FormData没错,XHR参数没错,请求地址也没错,后来才发现:跨域是浏览器的同源策略限制,和AJAX没关系,得让后端配置CORS

    什么是CORS?简单说就是后端告诉浏览器:“这个前端域名是安全的,你让它访问我吧”。具体要让后端加3个响应头:

  • Access-Control-Allow-Origin: https://你的前端域名.com(或者
  • 表示允许所有域名,但不推荐,不安全);

  • Access-Control-Allow-Methods: POST, GET, OPTIONS(允许的请求方法,上传一般用POST);
  • Access-Control-Allow-Headers: Content-Type(允许的请求头,FormData会自动加Content-Type: multipart/form-data,所以得允许这个头)。

    要是你传了自定义头信息(比如

    Authorizationtoken),后端还得加Access-Control-Allow-Headers: Authorization。我当时和后端说清楚后,他5分钟就配置好了,跨域问题一下子就解决了——原来之前的报错,根本不是我的问题!

    下面这个表格,是我整理的AJAX上传 vs 传统表单上传的区别,你一看就明白为什么AJAX更好用:

    对比项 传统表单上传 AJAX上传
    页面刷新 是(会丢失表单内容) 否(无刷新体验)
    进度监控 无法实现 可以精准显示上传百分比
    大文件支持 容易超时/卡顿 可分片上传,稳定性高
    用户体验 差(刷新后得重新填内容) 好(实时反馈上传状态)

    你要是按这些方法试了,欢迎回来告诉我效果!要是遇到什么奇怪的问题——比如进度条突然跳满,或者分片合并后文件损坏——评论区留个言,我帮你想想办法——毕竟这些坑我都踩过,说不定能帮你省点时间~


    你是不是经常遇到要传好几个文件的情况?比如做商品详情页要传5-10张不同角度的图,或者传客户案例要传一组照片?其实AJAX完全能搞定多文件上传,步骤跟单文件差不多,就多两步小操作。首先得给文件输入框加个multiple属性——把原来的改成,这样用户选文件时就能像在电脑上选文件一样,按住Ctrl键点选多个,或者拖个框选一片,不用再点好几次“选择文件”。我之前帮朋友做婚纱摄影的案例上传功能,就这么改了一下,用户反馈说“终于不用传一张等一张了”。

    选好多个文件后,JS处理也不复杂。之前单文件是拿e.target.files[0],多文件就是直接拿e.target.files这个数组,里面每个元素都是选好的文件对象。接下来只要循环这个数组,把每个文件加到FormData里就行——比如用forEach遍历,每遍历一个就调用formData.append('file', 当前文件)。这里有个小技巧:FormData的append方法允许同一个键名加多次,不用改成file1file2这种,就用同一个file键名,服务器端收到会自动当成列表处理。比如PHP里用$_FILES['file']能拿到所有文件,Python Django用request.FILES.getlist('file')也能拿到,后端不用改太多代码。我之前用这个方法传过8张1MB左右的商品图,不到2秒就传完了,页面没刷新,用户还能接着填商品名字和描述,体验比传统表单好太多。


    FormData在老浏览器里能用吗?

    FormData的兼容性很好,IE10及以上版本的浏览器都支持,Chrome、Firefox、Safari等现代浏览器也都兼容。如果你的网站不需要兼容IE9及以下,完全可以放心用;如果要兼容更老的浏览器,可能需要用Flash或其他替代方案,但现在大部分场景下FormData已经足够覆盖。

    AJAX上传能同时传多个文件吗?

    可以的。只需要给文件输入框加个multiple属性(比如),用户选文件时就能选多个。然后在JS里循环e.target.files数组,把每个文件都用formData.append('file', 文件对象)加进去就行——服务器端只要按多个文件的逻辑接收就行。

    为什么进度条没反应?

    大概率是进度事件绑错了地方!进度事件要绑定在xhr.upload对象上,而不是xhr本身。因为xhr.upload负责监听上传阶段的进度,xhr本身的进度事件是监听下载阶段的(比如服务器返回数据的进度)。把onprogress事件绑到xhr.upload上,进度条就能正常显示了。

    跨域报错是AJAX代码的问题吗?

    不是的。跨域报错是浏览器的同源策略限制,和AJAX代码没关系,得让后端配置CORS(跨域资源共享)。具体来说,后端需要在响应头里加三个字段:Access-Control-Allow-Origin(允许的前端域名)、Access-Control-Allow-Methods(允许的请求方法,比如POST)、Access-Control-Allow-Headers(允许的请求头,比如Content-Type)。配置好这些,跨域问题就能解决。

    多大的文件需要用分片上传?

    没有固定的数字标准,一般 100MB以上的文件用分片上传。因为大文件直接传容易超时、卡顿,或者因为网络波动导致上传失败——分片上传能把大文件切成小份,就算某一份传失败,只需要重传那一份,不用整个文件重新传,稳定性更高。如果你的文件大部分是几MB的小图,直接传就行,没必要分片。

  • 温馨提示:本站提供的一切软件、教程和内容信息都来自网络收集整理,仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负,版权争议与本站无关。用户必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。如果您喜欢该程序和内容,请支持正版,购买注册,得到更好的正版服务。我们非常重视版权问题,如有侵权请邮件与我们联系处理。敬请谅解! 联系邮箱:lgg.sinyi@qq.com

    给TA打赏
    共{{data.count}}人
    人已打赏
    行业资讯

    查看网站源码工具大全|免费在线+本地常用软件全推荐

    2025-9-10 11:35:09

    行业资讯

    php准确获取标准北京时间|简单几步实战方法

    2025-9-10 11:35:17

    0 条回复 A文章作者 M管理员
      暂无讨论,说说你的看法吧
    个人中心
    购物车
    优惠劵
    今日签到
    有新私信 私信列表
    搜索