侧边栏壁纸
  • 累计撰写 28 篇文章
  • 累计创建 9 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

解决阿里云大文件无法上传问题

仓鼠
2024-12-29 / 0 评论 / 0 点赞 / 12 阅读 / 6323 字 / 正在检测是否收录...

解决阿里云大文件无法上传问题

最近开发上传oss功能时,考虑到不想走服务器流量,就打算使用临时密钥的方式。

具体的技术方案

https://cloud.tencent.com/document/product/436/14048

后端的核心代码如下

public CtYunOssTemporaryVo temporary(List<CtYunOssTemporaryDTO> dto) {
      String code = StrUtil.nullToDefault(AuthUtil.getCode(),"default");
      TreeMap<String, Object> config = new TreeMap<String, Object>();
      config.put("secretId", secretIdTx);
      config.put("secretKey", secretKeyTx);
      Policy policy = new Policy();
      config.put("durationSeconds", 1800);
      config.put("bucket", endpointTx);
      config.put("region", regionTx);
      Statement statement = new Statement();
      statement.setEffect("allow");
      statement.addActions(new String[]{
              "cos:PutObject",
              "cos:PostObject",
              "ci:CreateFileProcessJobs"
      });
      List<String> resources = new ArrayList<>();

      List<CtYunOssTemporaryFileVo> fileList = new ArrayList<>();
      for (CtYunOssTemporaryDTO temporaryDTO : dto) {
          String suffix = temporaryDTO.getSuffix();
          if (StrUtil.isEmpty(suffix)) {
              throw new ApiResultException("文件" + temporaryDTO.getFileName() + "后缀不能为空");
          }
          CtYunOssTemporaryFileVo fileVo = BeanUtil.toBean(temporaryDTO, CtYunOssTemporaryFileVo.class);
          String uid = IdUtil.fastSimpleUUID();
          String key = '生成唯一key';
          //qcs::cos:ap-beijing:uid/1250000000:examplebucket-1250000000/doc2/*
          String format = String.format("qcs::cos:%s:uid/%s:%s/%s", endpointTx, uidTx, bucketNameTx,key);
          resources.add(format);

          //日志数据
          SysFiles entity = new SysFiles();
          entity.setPermission(FilePermissionEnum.PUBLIC.name());
          entity.setId(IdUtil.getSnowflake(0, 0).nextId());
          entity.setGroupName("cos-temporary");
          entity.setName(temporaryDTO.getFileName());
          entity.setType(suffix);
          entity.setAbsolutePath(pathTx + key);
          entity.setRelativePath(key);
          dao.insert(entity);

          fileVo.setFileId(uid);
          fileVo.setKey(key);
          fileVo.setAbsolutePath(pathTx + key);
          fileList.add(fileVo);
      }
      statement.addResources(resources.toArray(new String[0]));

      policy.addStatement(statement);
      config.put("policy", Jackson.toJsonPrettyString(policy));
      try {
          Response response = CosStsClient.getCredential(config);
          if(response == null || response.credentials == null || response.credentials.tmpSecretKey == null){
            throw new ApiResultException("无法获取上传密钥");
          }
          return CtYunOssTemporaryVo.builder()
                  .tmpSecretId(response.credentials.tmpSecretId)
                  .tmpSecretKey(response.credentials.tmpSecretKey)
                  .sessionToken(response.credentials.sessionToken)
                  .startTime(response.startTime)
                  .expiredTime(response.expiredTime)
                  .bucket(bucketNameTx)
                  .region(regionTx)
                  .fileList(fileList)
                  .build();
      } catch (IOException e) {
        e.printStackTrace();
          throw new ApiResultException("上传权限获取异常");
      }
  }

因为从后端的思维,之前服务器上传的时候,我们正常采用的时put请求和post请求将数据发送到服务器端,所以将demo中的

文档提供的

statement.addActions(new String[]{
              "cos:PutObject",
              // 分块上传
              "cos:InitiateMultipartUpload",
              "cos:ListMultipartUploads",
              "cos:ListParts",
              "cos:UploadPart",
              "cos:CompleteMultipartUpload",
              // 表单上传、小程序上传
              "cos:PostObject",
              // 文件压缩
              "ci:CreateFileProcessJobs"
      });

//

我写的 考虑到最低权限赋值

statement.addActions(new String[]{
              "cos:PutObject",
              "cos:PostObject",
              "ci:CreateFileProcessJobs"
      });

问题的产生

在和前端的联调中发现并没有问题,直到测试上传了一个大文件,发现上传不上去


<Error>
	<Code>AccessDenied</Code>
	<Message>
	Access Denied.
	</Message>
	<ServerTime>
	2024-12-26T06:35:31Z
	</ServerTime>
	<Resource>/</Resource>
<RequestId>
	Njc2Y2Y5MzNfODg3MDgxMGJfMTkzZDdfMTAwNDM3MA==
</RequestId>
<TraceId>
OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTBjYzE2MjAxN2M1MzJiOTdkZjMxMDVlYTZjN2FiMmI0NTZkM2E5M2VhMDJhYmRiMjFmNGRlMGQ5YTgxNzQzYmM=
</TraceId>
</Error>

通过下载官方的sdk 和demo发现,在前端上传大文件时,请求不是PUT而是GET

通过查看代码发现,有个 SliceSize 属性

// 监听选文件
document.getElementById('file-selector').onchange = function () {

    var file = this.files[0];
    if (!file) return;

    // 上传文件
    cos.uploadFile({
        Bucket: Bucket,
        Region: Region,
        Key: file.name,
        Body: file,
        SliceSize: 10 * 1024 * 1024, // 大于1mb才进行分块上传
        onTaskReady: function (tid) {
          taskId = tid;
        },
        onProgress: function (progressData) {
            console.log('上传中', JSON.stringify(progressData));
        },
    }, function (err, data) {
        console.log(err, data);
    });

    // 可使用队列暂停、重启任务
    // cos.pauseTask(taskId);

};

所以发现,10M上传转换成了分片上传,所以需要将下列一并添加到权限中

// 分块上传
"cos:InitiateMultipartUpload",
"cos:ListMultipartUploads",
"cos:ListParts",
"cos:UploadPart",
"cos:CompleteMultipartUpload",

0

评论区