Android端使用presigned URLs向S3实现multipart upload的方案咨询
Android端通过预签名URL向S3实现分块上传的最佳实践
核心问题解决:Retrofit动态URL适配
你遇到的Retrofit仅支持固定接口地址的问题,实际可以通过@Url注解直接绕过全局BaseUrl限制,直接给每个分片请求传入单独的预签名URL,接口定义示例如下:
interface S3MultipartApi { // 直接将预签名URL作为第一个参数传入,优先级高于全局BaseUrl @PUT suspend fun uploadSinglePart( @Url presignedUrl: String, @Body partBody: RequestBody ): Response<Unit> }
请求发起时直接传入对应分片的预签名URL即可,无需调整全局Retrofit配置。
完整上传流程实现
- 第一步:向业务后端发起分块上传初始化请求,获取S3分配的
uploadId,以及每个分片对应的预签名URL(可按分片编号动态生成,也可一次性拉取全部分片的预签名地址) - 第二步:将本地待上传文件按5MB~10MB的大小切分(S3要求除最后一个分片外,其余分片最小为5MB,最大支持5GB),为每个分片分配从1开始的连续编号
- 第三步:控制并发上传数,建议同时上传的分片不超过3个,避免网络拥塞导致请求失败,可通过协程的
async+awaitAll或者自定义线程池实现 - 第四步:每个分片上传成功后,从返回头中提取
ETag字段,和对应分片编号绑定存储,该字段是后续完成分块上传的必填参数 - 第五步:所有分片上传完成后,将分片编号+ETag的集合传给业务后端,触发S3的CompleteMultipartUpload接口调用,完成整个文件的合并
稳定性优化方案
自动重试实现
给OkHttp配置自定义重试拦截器,针对5xx服务端错误、网络超时、连接断开等异常场景自动重试,重试次数建议配置为3~5次。S3的分片上传为幂等操作,重复上传同一分片不会导致数据异常。
断点续传实现
本地持久化存储已上传成功的分片编号和对应ETag,APP重启、网络中断恢复后,跳过已完成的分片,仅上传剩余未上传的部分,无需从头开始上传。
网络波动适配
接入Android系统网络状态监听能力,网络断开时自动暂停所有上传任务,网络恢复后自动从断点处续传,无需用户手动操作。
数据正确性校验
每个分片上传完成后,将本地计算的分片哈希值和S3返回的ETag做对比,若不一致则自动重传该分片,避免上传数据损坏。
注意事项
- 预签名URL的有效期需要设置足够长,至少大于预估的最大文件上传耗时,避免分片还未上传完成URL就过期
- 分片上传请求不要额外添加
Authorization等自定义请求头,预签名URL已经自带签名信息,多余的请求头会导致S3签名校验失败 - 若需要监听上传进度,可自定义
RequestBody实现写入进度回调,累加所有分片的上传进度即可得到整体文件的上传进度
内容的提问来源于stack exchange,提问作者am1987
相关产品推荐
相关产品推荐

