文件服务(二)
概括
-
1)客户端调用
InitUploadFileUrl(fileName, fileSize, contentType)
服务端向 MinIO 发起分片会话(拿到UploadId和最终对象Key),按固定分片大小(6MB)生成每一片的预签名 PUT URL 列表并返回(含每片的PartNumber/Url/StartByte/EndByte)。 -
2)客户端按返回的分片信息切文件并直接 PUT 到 MinIO
每片用对应的预签名 URL 上传;上传成功后从响应里取到该片的ETag,收集成PartETagList = [{PartNumber, ETag}, ...]。 -
3)客户端调用
ChunkMultipartUploadUrl提交合并
把每个文件的Key + UploadId + PartETagList传回服务端;服务端调用 MinIO 的CompleteMultipartUpload(会按PartNumber排序)生成最终对象,然后写入业务数据库(记录 Path=Key 等),返回业务结果。 -
4)如需取消上传,客户端调用
CancelMultipartUploadUrls
传key + uploadId,服务端调用AbortMultipartUpload,MinIO 清理该上传会话的临时分片。
知识点:MinIO 分片上传(预签名 URL 模式)在本项目里的实现
- 关联入口(Controller)
- 初始化并返回预签名 URL:[KnowController.InitUploadFileUrl](file:///d:/ceshi/MedicTechServer/MedicTechServer/Controllers/KnowController.cs#L794-L819)
- 合并分片(支持多文件):[KnowController.ChunkMultipartUploadUrls](file:///d:/ceshi/MedicTechServer/MedicTechServer/Controllers/KnowController.cs#L821-L855)
- 取消上传(Abort):[KnowController.CancelMultipartUploadUrl](file:///d:/ceshi/MedicTechServer/MedicTechServer/Controllers/KnowController.cs#L858-L878)
- 关联实现(Service)
- 生成预签名 URL:[MinioService.GeneratePresignedUrl](file:///d:/ceshi/MedicTechServer/MedicTechServer/Services/MinioService.cs#L402-L419)
- 初始化分片会话 + 批量生成 URL:[MinioService.InitMultipartUploadForURL](file:///d:/ceshi/MedicTechServer/MedicTechServer/Services/MinioService.cs#L421-L495)
- 合并分片(会排序 PartNumber):[MinioService.CompleteMultipartUploadForURL](file:///d:/ceshi/MedicTechServer/MedicTechServer/Services/MinioService.cs#L497-L522)
- 取消分片会话:[MinioService.AbortUploadForURL](file:///d:/ceshi/MedicTechServer/MedicTechServer/Services/MinioService.cs#L524-L542)
1) 这套模式解决什么问题?
- 与“服务端中转上传分片”不同:这里服务端只负责“签发上传 URL + 最终合并”,真正的分片数据由客户端直接 PUT 到 MinIO。
- 优点:服务端带宽/CPU 压力小;分片可并发 PUT;上传更接近对象存储的标准用法。
2) 初始化:签发 UploadId + Key + 每片的预签名 PUT URL
对应:[InitUploadFileUrl](file:///d:/ceshi/MedicTechServer/MedicTechServer/Controllers/KnowController.cs#L794-L819) → [InitMultipartUploadForURL](file:///d:/ceshi/MedicTechServer/MedicTechServer/Services/MinioService.cs#L421-L495)
关键点:
- 服务端先调用
InitiateMultipartUpload得到UploadId,同时生成对象Key = Guid + 文件名(防重名)。 - 固定分片大小:
chunkSize = 6MB(6 * 1024 * 1024)。 - 每个分片生成一个预签名 URL:HTTP PUT、有效期 2 小时、强制 HTTPS、带上
UploadId + PartNumber。- 见 [GeneratePresignedUrl](file:///d:/ceshi/MedicTechServer/MedicTechServer/Services/MinioService.cs#L402-L419)
伪代码:
InitUploadFileUrl(fileName, fileSize, contentType):
init = minio.initiateMultipart(
bucket="medic-tech",
key=Guid + "_" + fileName,
contentType=contentType
)
chunkSize = 6MB
totalChunks = 根据 fileSize 和 chunkSize 计算
urls = []
for partNumber in 1..totalChunks:
url = minio.presignPutPartUrl(
bucket, key=init.key, uploadId=init.uploadId, partNumber,
expires=2h, protocol=https
)
urls.add({partNumber, url, startByte, endByte})
return { uploadId: init.uploadId, key: init.key, chunkSize, totalChunks, chunkUrls: urls }
客户端要做的事(核心知识点):
- 按
startByte/endByte切片后,对每片的url执行 HTTP PUT 上传。 - 每次 PUT 成功后,从响应头拿到
ETag,记录成{ PartNumber, ETag },用于最终合并。
3) 合并:客户端带着 PartETagList 回来,服务端 Complete 并写库
对应:[ChunkMultipartUploadUrls](file:///d:/ceshi/MedicTechServer/MedicTechServer/Controllers/KnowController.cs#L821-L855) → [CompleteMultipartUploadForURL](file:///d:/ceshi/MedicTechServer/MedicTechServer/Services/MinioService.cs#L497-L522)
关键点:
- 入参
uploadFormUrl files支持多个文件同时合并:files.mutipartFormItems。 - 每个文件都必须携带:
Key + UploadId + PartETagList。 - Service 里会按
PartNumber排序再 Complete(避免乱序导致合并失败/不稳定):- [MinioService.cs:L511-L517](file:///d:/ceshi/MedicTechServer/MedicTechServer/Services/MinioService.cs#L511-L517)
- 合并成功后,用
compResponse.Key作为文件在 MinIO 的最终路径,并调用_knowSe.AddSingleKnow(...)写入业务数据。
伪代码:
ChunkMultipartUploadUrls(files):
resData = []
for item in files.mutipartFormItems:
completeResp = minio.completeMultipart(
bucket="medic-tech",
key=item.Key,
uploadId=item.UploadId,
partETags=sortByPartNumber(item.PartETagList)
)
know = business.addSingleKnow(
code=files.code, orgId, userId, role,
uploadMeta=item,
path=completeResp.Key
)
resData.add({ id: know.id, name: know.name })
return resData
4) 取消:AbortMultipartUpload 清理 MinIO 侧临时分片
对应:[CancelMultipartUploadUrl](file:///d:/ceshi/MedicTechServer/MedicTechServer/Controllers/KnowController.cs#L858-L878) → [AbortUploadForURL](file:///d:/ceshi/MedicTechServer/MedicTechServer/Services/MinioService.cs#L524-L542)
关键点:
- 客户端只要提供
key + uploadId,服务端调用 Abort 即可让 MinIO 清掉该上传会话的临时分片。
伪代码:
CancelMultipartUploadUrl(cancelFormList):
for each c in cancelFormList:
minio.abortMultipart(bucket="medic-tech", key=c.key, uploadId=c.uploadId)
return OK
5) 最小注意点(以后排查问题用)
- 预签名 URL 有效期 2 小时:过期后 PUT 会失败,需要重新 Init。
- 合并必须提供完整且正确的
PartETagList(PartNumber 对应的 ETag 不能错/不能漏)。 - 这套模式不依赖服务端内存缓存(与另一套 UploadFiles/UploadSubmit 不同),上传状态主要由客户端维护并回传。

浙公网安备 33010602011771号