1. 项目概述
在能源化工行业的生产运营中,经常需要在局域网环境下传输大型工程文件(如CAD图纸、工艺模拟数据、设备监测日志等),这些文件通常体积庞大(从几百MB到几十GB不等),且对传输可靠性要求极高。传统的FTP或共享文件夹方式在遇到网络波动或系统中断时,往往需要重新传输整个文件,严重影响了工作效率。
WebUploader作为一款基于浏览器的文件上传组件,通过分片上传和断点续传机制,能够有效解决局域网大文件传输的痛点。我在某石化企业DCS系统升级项目中,就曾用这套方案成功实现了单日300+GB工艺数据的稳定传输。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心技术解析
2.1 分片上传机制
大文件传输的核心在于将文件拆分为多个小块(通常2-10MB)。我们通过以下代码实现分片:
javascript复制// 获取文件对象
const file = document.getElementById('file').files[0];
const chunkSize = 5 * 1024 * 1024; // 5MB分片
const totalChunks = Math.ceil(file.size / chunkSize);
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize;
const end = Math.min(file.size, start + chunkSize);
const chunk = file.slice(start, end);
// 为每个分片生成唯一标识
const chunkId = CryptoJS.MD5(`${file.name}_${i}`).toString();
uploadChunk(chunkId, chunk, i, totalChunks);
}
关键点:分片大小需要根据局域网实际带宽调整。在千兆局域网中,5MB分片能平衡传输效率和容错能力。
2.2 断点续传实现
断点续传依赖三个关键技术点:
- 分片标识管理:每个分片需包含文件指纹(MD5)、分片序号、总分片数
- 传输状态记录:服务端用Redis记录已接收分片
- 异常恢复机制:客户端通过接口查询缺失分片
服务端状态记录示例(Spring Boot):
java复制@PostMapping("/checkChunk")
public ResponseEntity<Map<String, Object>> checkChunk(
@RequestParam String fileMd5,
@RequestParam Integer chunkIndex) {
String redisKey = "upload:" + fileMd5;
Boolean exists = redisTemplate.opsForHash().hasKey(redisKey, chunkIndex.toString());
Map<String, Object> response = new HashMap<>();
response.put("exists", exists);
return ResponseEntity.ok(response);
}
3. 能源化工场景适配
3.1 行业特殊需求
在炼化厂区局域网环境中,我们遇到了以下典型问题:
- 工业协议干扰:Modbus/TCP等协议可能占用带宽
- 安全限制:防病毒软件会扫描传输中的文件
- 老旧设备:部分工控机仍在使用IE浏览器
解决方案:
- 采用WebSocket替代HTTP提升传输效率
- 白名单设置排除防病毒软件干扰
- 为IE浏览器提供ActiveX插件兼容方案
3.2 性能优化参数
经过实测,某乙烯项目中的最优参数配置:
| 参数项 | 办公网络设置 | 生产网络设置 |
|---|---|---|
| 分片大小 | 5MB | 2MB |
| 并发线程数 | 6 | 3 |
| 超时时间 | 60s | 120s |
| 重试次数 | 3 | 5 |
注意:生产网络因存在DCS系统流量,需要更保守的参数配置
4. 完整实现方案
4.1 前端关键代码
采用Web Worker实现后台分片处理:
javascript复制// upload.worker.js
self.onmessage = function(e) {
const { file, chunkSize } = e.data;
const reader = new FileReader();
reader.onload = function(event) {
const chunk = event.target.result;
self.postMessage({
chunk: chunk,
index: currentChunk
});
};
reader.readAsArrayBuffer(
file.slice(offset, offset + chunkSize)
);
};
4.2 服务端架构
基于Spring Boot的接收服务:
java复制@RestController
@RequestMapping("/upload")
public class UploadController {
@PostMapping("/chunk")
public ResponseEntity<String> uploadChunk(
@RequestParam String fileMd5,
@RequestParam Integer chunkIndex,
@RequestParam Integer totalChunks,
@RequestParam MultipartFile chunk) {
// 临时存储分片
String tempDir = "/data/temp/" + fileMd5;
Files.createDirectories(Paths.get(tempDir));
String chunkPath = tempDir + "/" + chunkIndex;
chunk.transferTo(new File(chunkPath));
// 记录分片状态
redisTemplate.opsForHash().put(
"upload:" + fileMd5,
chunkIndex.toString(),
"1");
// 检查是否全部完成
if (redisTemplate.opsForHash().size("upload:" + fileMd5) == totalChunks) {
mergeFiles(fileMd5, totalChunks);
}
return ResponseEntity.ok("success");
}
}
5. 实战问题排查
5.1 典型故障案例
案例1:分片合并后MD5校验失败
- 现象:文件能合并但校验不通过
- 原因:网络抖动导致分片数据损坏
- 解决方案:增加分片级MD5校验
java复制// 分片接收时增加校验
String chunkMd5 = DigestUtils.md5Hex(chunk.getBytes());
if (!chunkMd5.equals(request.getHeader("Content-MD5"))) {
throw new RuntimeException("分片校验失败");
}
案例2:IE浏览器上传中断
- 现象:上传到30%自动停止
- 原因:IE的XMLHttpRequest有2GB限制
- 解决方案:改用WebSocket或ActiveX控件
5.2 性能监控方案
建议部署以下监控指标:
- 分片传输成功率
- 平均传输速率
- 重试频率
- 合并耗时
使用Prometheus采集示例:
yaml复制metrics:
upload_speed:
type: gauge
help: "文件上传速率(MB/s)"
labels: [project, department]
chunk_retries:
type: counter
help: "分片重试次数"
6. 进阶优化方向
对于特别关键的生产数据(如SCADA历史数据库),我们进一步实现了:
- 双通道传输:同时使用HTTP和WebSocket通道
- 智能分片:根据实时网络质量动态调整分片大小
- CRC校验:每10个分片做一次循环冗余校验
- 本地缓存:浏览器IndexedDB存储已上传分片信息
优化后的传输性能对比:
| 优化措施 | 传输速率提升 | 失败率下降 |
|---|---|---|
| 双通道传输 | 35% | 60% |
| 动态分片 | 28% | 45% |
| CRC校验 | -5% | 80% |
在实际项目中,这套方案成功实现了:
- 单文件50GB P&ID图纸的稳定传输
- 2000+台设备日志的并发采集
- 99.99%的传输成功率
