1. 项目背景与需求拆解
1.1 为什么我最终选了WebUploader做分块上传
先交代一下项目背景。当时接到的是一个企业内部培训系统的文件管理模块,里面有个视频上传功能,教学视频动不动就是几百MB甚至1GB起步。最初用的就是Spring MVC标准的MultipartFile上传,结果上线没几天就被运维找上门了——服务器内存频繁告警,Nginx时不时报504超时,用户那边更直接,传个大文件传到一半断了就得从头再来,一天能接到十几个投诉工单。
这个场景你应该不陌生:用传统方式做文件上传,前端把整个文件塞进一次HTTP请求里,后端再一次性读取全部字节。小文件没问题,但文件一上GB,问题就全暴露出来了。首先是网络层,一次请求耗时太长,中间任何一次抖动、断连、服务器重启,整个上传就废了;其次是服务端,Servlet容器接收大文件时会把数据先写入内存或临时文件,并发一高内存就吃紧;再就是用户体验,进度条半天不动,用户根本不知道是死是活。
后来对比了市面上几款上传组件,最终敲定用WebUploader。理由很简单:它本身就是百度WebFE团队开源的东西,分块上传、并发上传、断点续传这些高频能力是原生支持的,API设计也不绕,前端配置半小时就能跑起来。关键是它没有强依赖框架,后端只需要按约定接收分块、合并分块就行,用Java写这部分逻辑非常顺手。下面我把完整步骤拆开讲,每一步都会说清楚为什么这么做,以及我在实际项目里踩过的坑。
1.2 分块上传这个方案到底解决了什么
分块上传的核心思路其实特别朴素:把一个大文件切成N个小块,一个一个传给服务器,服务器收齐所有分块后再拼成一个完整文件。
但朴素归朴素,它带来的收益是很实在的。第一个收益是失败成本大幅下降。5MB一个分块,传完一个就确认一个,第37块断了?重新传第37块就行,前面36块不用动。第二个收益是内存压力大幅缓解。后端每次只处理一个分块,对内存的消耗量级完全不一样。第三个收益是上传速度的质变。WebUploader支持多线程并发上传,默认并发数是3,也就是说同时有3个分块在飞,配合服务端分块独立落盘,整个上传吞吐量比单请求模式快很多。
还有一点容易被忽略:分块上传天然为秒传和断点续传做了铺垫。前端对文件算一个MD5,后端看到一个MD5就知道这个文件以前传没传过,如果传过了直接返回"已存在",这就是秒传。如果再配合一个查询接口,告诉前端哪些分块已经传过了,那前端只需要传缺失的块,这就是断点续传。这些能力放到现在的业务系统里,基本属于刚需。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 前端配置与分块策略设计
2.1 WebUploader核心参数到底怎么设
WebUploader使用上不复杂,但参数能不能设对,直接决定了后面是否踩坑。我当时的前端页面是基于jQuery的,WebUploader本身也依赖jQuery,所以先保证页面里引了正确版本的jQuery。初始化上传组件的代码大概长这样:
javascript复制var uploader = WebUploader.create({
swf: '/static/js/Uploader.swf',
server: '/api/upload/chunk',
pick: '#filePicker',
auto: false,
chunked: true,
chunkSize: 2 * 1024 * 1024,
threads: 3,
fileVal: 'file',
formData: {
module: 'training'
},
accept: {
title: 'Video',
extensions: 'mp4,avi,mov,flv'
}
});
这里有几个参数我重点说明一下,因为很多人就是在这里设错的。首先是chunked和chunkSize,chunked设为true代表开启分块,chunkSize控制每块大小。我为什么选2MB而不是10MB或50MB?因为分块越小,单块的传输时间越短,失败重传的成本越低,但分块数量会变多,发起请求的次数也会变多;分块越大,请求次数越少,但单块传输时间变长,网络抖动导致的失败影响面更大。实测下来2MB到5MB是性价比比较稳的区间,教学视频场景我直接用了2MB,分块数量和对服务端临时存储的压力都可控。
然后是threads,这个是并发上传的线程数。WebUploader默认是3,这个值不用贪大,因为浏览器对同一域名的TCP连接数是有限制的,而且并发太高会给后端造成不必要的压力,尤其是分块落盘时如果临时文件没有做很好的隔离,可能会出现并发写同一个文件的问题。我项目里3个并发,上传1GB文件体感速度已经比单线程快了两三倍。
fileVal也很关键,它决定了后端接收文件时用哪个参数名。WebUploader默认的文件参数名是file,很多人会在后端写成MultipartFile file,但前端忘了设置fileVal,或者改成了别的名字,结果后端一直接不到文件。这个参数前后端必须严格对齐,不然就是最常见的"上传了但后端没收到"的尴尬情况。
2.2 分块信息怎么传给后端
前端只把文件分块传过去是不够的,后端还需要知道每一块是属于哪个文件的、是哪一块、总共多少块。这些信息WebUploader会通过额外的请求参数带过去,默认参数名分别是chunk、chunks、name、guid。其中chunk是当前分块的索引(从0开始),chunks是总块数,name是原始文件名,guid是WebUploader为文件生成的唯一标识。
你可以在uploader的uploadBeforeSend回调里看到这些参数,也可以在这里对
