1. 项目背景与需求分析
在芯片制造企业的信息化建设中,大文件的安全传输一直是个棘手问题。我们经常需要处理10GB以上的设计图纸、工艺参数和测试数据,这些文件不仅体积庞大,而且包含核心商业机密。传统FTP或HTTP上传方式存在诸多痛点:
- 传输中断风险:网络波动导致大文件上传失败,需要从头开始
- 安全隐患:明文传输易被窃取,不符合行业安全规范
- 性能瓶颈:单线程上传效率低,无法充分利用带宽
针对这些问题,我们设计了一套基于Vue+SpringBoot的解决方案,核心特性包括:
- 分片上传/下载(5MB每片)
- 国密SM4端到端加密
- 断点续传支持
- 信创环境全兼容
提示:选择5MB分片大小是经过实测的平衡点 - 过小会增加请求开销,过大则失去分片意义。在100M带宽下,该配置可实现90%+的带宽利用率。
2. 技术架构设计
2.1 整体架构
code复制前端(Vue) → 传输加密(SM4) → 后端(SpringBoot)
↑ ↓
分片管理 加密存储
2.2 关键技术选型
前端技术栈
- Vue 2.x:兼容企业现有技术体系
- Web Crypto API:生成随机密钥/IV
- WebAssembly:SM4加密性能优化(比纯JS快3-5倍)
后端技术栈
- Spring Boot 2.7:提供RESTful接口
- BouncyCastle:国密算法支持
- NIO文件操作:高效处理分片合并
3. 前端实现详解
3.1 加密模块设计
javascript复制// sm4-utils.js
export async function initSM4() {
try {
// 优先加载WASM版本
const sm4Wasm = await import('sm4-wasm')
await sm4Wasm.default()
return {
encrypt: sm4Wasm.encrypt,
decrypt: sm4Wasm.decrypt
}
} catch (e) {
// 降级使用JS实现
const sm4Js = await import('./sm4-js')
return sm4Js
}
}
关键点:
- WASM优先策略保证性能
- 自动降级机制确保兼容性
- CBC模式提供更好的安全性
3.2 上传组件核心逻辑
javascript复制// FileUploader.vue
methods: {
async uploadChunk(chunk, index) {
const encrypted = await this.sm4.encrypt(
chunk,
this.encryptionKey,
this.iv
)
const formData = new FormData()
formData.append('fileId', this.fileId)
formData.append('chunk', new Blob([encrypted]))
formData.append('index', index)
await axios.post('/api/upload/chunk', formData, {
onUploadProgress: e => {
this.updateProgress(index, e.loaded)
}
})
}
}
4. 后端实现关键点
4.1 SM4加密工具类
java复制public class SM4Util {
public static byte[] encrypt(byte[] key, byte[] iv, byte[] input) {
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new SM4Engine())
);
cipher.init(true, new ParametersWithIV(
new KeyParameter(key), iv
));
byte[] output = new byte[cipher.getOutputSize(input.length)];
int len = cipher.processBytes(input, 0, input.length, output, 0);
len += cipher.doFinal(output, len);
return Arrays.copyOf(output, len);
}
}
4.2 分片合并策略
java复制// FileUploadController.java
@PostMapping("/complete")
public void completeUpload(@RequestBody CompleteRequest request) {
// 按分片序号排序合并
List<Path> chunks = getSortedChunks(request.fileId());
try (OutputStream out = Files.newOutputStream(getOutputPath())) {
for (Path chunk : chunks) {
byte[] decrypted = SM4Util.decrypt(key, iv, Files.readAllBytes(chunk));
out.write(decrypted);
}
}
cleanTempFiles(request.fileId());
}
5. 信创环境适配方案
5.1 前端兼容性处理
| 环境 | 测试要点 | 解决方案 |
|---|---|---|
| 麒麟OS | WASM支持 | 提供JS降级方案 |
| 龙芯CPU | 加密性能 | 优化分片大小 |
| 360浏览器 | API兼容 | 检测并polyfill |
5.2 后端适配经验
- 中科方德JDK需添加
-Dorg.bouncycastle.sm2.disable_sm3hash=true参数 - 华为Kunpeng环境下建议开启
-XX:+UseAESCTRIntrinsics优化 - 统信UOS需要手动安装bcprov-jdk15to18依赖
6. 安全增强措施
6.1 密钥管理方案
code复制客户端生成临时密钥 → 通过RSA加密 → 传输到服务端
↓
服务端用HSM解密 → 存入临时密钥库
6.2 防御性编程要点
- 分片校验:MD5校验每个分片完整性
- 大小验证:最终文件大小必须与声明一致
- 权限控制:上传目录不可执行
7. 性能优化记录
通过以下优化将10GB文件上传时间从4.2小时缩短至28分钟:
- 并发上传:5个分片并行传输(需服务端支持)
- 内存优化:使用Stream处理分片避免OOM
- 零拷贝合并:Java的FileChannel.transferTo
实测数据:100M带宽下,加密开销仅增加15%传输时间
8. 实际部署问题排查
问题1:分片顺序错乱
- 现象:合并后文件损坏
- 原因:网络延迟导致分片到达乱序
- 解决:服务端按index重新排序
问题2:内存泄漏
- 现象:长时间运行后服务崩溃
- 定位:未关闭的FileInputStream
- 修复:try-with-resources重构
9. 扩展功能实现
9.1 文件夹上传
javascript复制// 递归处理文件夹
async uploadFolder(folder) {
for (const entry of folder.entries()) {
if (entry.isDirectory) {
await this.uploadFolder(entry)
} else {
await this.uploadFile(entry)
}
}
}
9.2 断点续传实现
- 前端保存已上传分片记录到localStorage
- 服务端提供分片状态查询接口
- 恢复时跳过已上传分片
10. 效果验证数据
测试环境:Intel Xeon 2.4GHz, 16GB内存, 千兆网络
| 文件大小 | 传统方式 | 本方案 | 提升 |
|---|---|---|---|
| 1GB | 3m12s | 1m45s | 45% |
| 10GB | 32m | 28m | 13% |
| 100GB | 失败 | 4h22m | - |
注:小文件优势不明显,但大文件稳定性显著提升