乐趣区

关于阿里云:antd-Upload组件上传文件到阿里云OSS

前言

阿里云 oss 上传文件蕴含有好多 SDK,个别像客户端的百度云盘这样的 C 端会应用如 java 相干的 SDK,而浏览器端,也就是 web 端最好应用 browser.js 相干的 SDK, 上面就来解说下如何应用,心愿可能帮忙到大家。

配置 ram 权限获取 sts token 和跨域反对

在应用阿里云 OSS 上传文件之前,要提前配置好 ram 相干权限,官网文档有阐明,具体请看应用 STS 长期拜访凭证拜访 OSS,配置时,要留神两点:
1、因为会应用上传和下载两种权限,所以应该应用上面权限策略(xxx 为你的门路):

{
    "Version": "1",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "oss:PutObject",
                "oss:GetObject"
            ],
            "Resource": [
                "acs:oss:*:*:xxx",
                "acs:oss:*:*:xxx/*"
            ]
        }
    ]
}

配置好之后,咱们再来配置后盾,返回 sts token 给前端

 @Override
    public AssumeRoleResponse getAcsForUploadFile(String userName) {
        // STS 接入地址,例如 sts.cn-hangzhou.aliyuncs.com。String endpoint = aliyunOssConfig.getRamStsEndpoint();
        // 填写步骤 1 生成的拜访密钥 AccessKey ID 和 AccessKey Secret。String AccessKeyId = aliyunOssConfig.getRamAccessKeyId();
        String accessKeySecret = aliyunOssConfig.getRamAccessKeySecret();
        // 填写步骤 3 获取的角色 ARN。String roleArn = aliyunOssConfig.getRamRoleArn();
        // 自定义角色会话名称,用来辨别不同的令牌,例如可填写为 SessionTest。String roleSessionName = userName;
        // 以下 Policy 用于限度仅容许应用长期拜访凭证向指标存储空间 examplebucket 上传文件。// 长期拜访凭证最初取得的权限是步骤 4 设置的角色权限和该 Policy 设置权限的交加,即仅容许将文件上传至指标存储空间 examplebucket 下的 exampledir 目录。//        String policy = "{" +
//                "\"Version\": \"1\"," +
//                "\"Statement\": [" +
//                "{\n" +
//                "\"Action\": [" +
//                "\"oss:PutObject\"" +
//                "]," +
//                "\"Resource\": [" +
//                "\"acs:oss:*:*:com-seaurl-cdn/space\"," +
//                "\"acs:oss:*:*:com-seaurl-cdn/space/*\"," +
//                "]," +
//                "\"Effect\": \"Allow\"" +
//                "}" +
//                "]" +
//                "}";
        try {
            // regionId 示意 RAM 的地区 ID。以华东 1(杭州)地区为例,regionID 填写为 cn-hangzhou。也能够保留默认值,默认值为空字符串("")。String regionId = aliyunOssConfig.getRegion();
            // 增加 endpoint。实用于 Java SDK 3.12.0 及以上版本。DefaultProfile.addEndpoint(regionId, "Sts", endpoint);
            // 增加 endpoint。实用于 Java SDK 3.12.0 以下版本。// DefaultProfile.addEndpoint("",regionId,"Sts", endpoint);
            // 结构 default profile。IClientProfile profile = DefaultProfile.getProfile(regionId, AccessKeyId, accessKeySecret);
            // 结构 client。DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            // 实用于 Java SDK 3.12.0 及以上版本。request.setSysMethod(MethodType.POST);
            // 实用于 Java SDK 3.12.0 以下版本。//request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            request.setPolicy(null); // 如果 policy 为空,则用户将取得该角色下所有权限。request.setDurationSeconds(3600L); // 设置长期拜访凭证的无效工夫为 3600 秒。final AssumeRoleResponse response = client.getAcsResponse(request);
            System.out.println("Expiration:" + response.getCredentials().getExpiration());
            System.out.println("Access Key Id:" + response.getCredentials().getAccessKeyId());
            System.out.println("Access Key Secret:" + response.getCredentials().getAccessKeySecret());
            System.out.println("Security Token:" + response.getCredentials().getSecurityToken());
            System.out.println("RequestId:" + response.getRequestId());
            return response;
        } catch (com.aliyuncs.exceptions.ClientException e) {System.out.println("Failed:");
            System.out.println("Error code:" + e.getErrCode());
            System.out.println("Error message:" + e.getErrMsg());
            System.out.println("RequestId:" + e.getRequestId());
            return null;
        }
    }

2、设置跨域反对
如果设置了跨域规定还是不起作用,能够应用上面形式进行批改:
设置跨域规定后调用 OSS 时依然报“No ‘Access-Control-Allow-Origin’”的谬误

上传文件(简略上传和分片上传)

下面配置好权限之后,接下来咱们来装置和应用

1、装置ali-oss

yarn add ali-oss

2、初始化 oss client
留神:getAcsForUploadFile()办法就是下面获取 sts token 的申请办法

 // 初始化 oss client 客户端
  async function initOssClient() {let res = await dispatch(getAcsForUploadFile())
    console.log('initOss=', res)
    if (res.payload.status === 0) {
      const resData = res.payload.data
      const client = new OSS({
        secure: true,
        // yourRegion 填写 Bucket 所在地区。以华东 1(杭州)为例,Region 填写为 oss-cn-hangzhou。region: 'oss-cn-hangzhou',
        // 从 STS 服务获取的长期拜访密钥(AccessKey ID 和 AccessKey Secret)。accessKeyId: resData.credentials.accessKeyId,
        accessKeySecret: resData.credentials.accessKeySecret,
        // 从 STS 服务获取的平安令牌(SecurityToken)。stsToken: resData.credentials.securityToken,
        refreshSTSToken: async () => {
          // 向您搭建的 STS 服务获取长期拜访凭证。const refreshRes = await dispatch(getAcsForUploadFile())
          console.log('refreshSTSToken info=', refreshRes)
          if (refreshRes.payload.status === 0) {
            const refreshResData = refreshRes.payload.data
            return {
              accessKeyId: refreshResData.credentials.accessKeyId,
              accessKeySecret: refreshResData.credentials.accessKeySecret,
              stsToken: refreshResData.credentials.securityToken
            }
          }

        },
        // 刷新长期拜访凭证的工夫距离,单位为毫秒。refreshSTSTokenInterval: 3000000,
        // 填写 Bucket 名称。bucket: 'xxx'
      });
      if (client) {setOssClient(client)
      }
    }
  }

3、上传文件

 // 上传文件前判断单个文件是否超过 500mb,如果超过不容许上传
  function beforeUploadFile(file, fileList) {console.log('file=', file)
    const isLt500M = file.size / 1024 / 1024 > 500;
    if (isLt500M) {message.warning('超过最大文件上传大小 500Mb');
      return false
    }
    return true; // 不调用默认的上传办法
  }

 // 上传文件状态回调
  function onUploadFileChange(info) {console.log('info=', info)
    // 把没有 status 的文件过滤掉(没有 status 的文件阐明是勾销上传的文件)
    if (info.file.status) {
      setFileTaskDlg({
        show: true,
        task: info
      })
      if (info.file.status === 'done') {
        dispatch(getFileListByCid({cid: query.cid}))
      }
      if (info.file.status === 'error') {
        dispatch(getFileListByCid({cid: query.cid}))
      }
    }
  }

// 自定义上传
  function uploadFileToOss(options) {console.log('options=', options)
    const {file, onProgress, onSuccess, onError} = options

    return new Promise(async (resolve, reject) => {const filePath = `space/file/${me.name}/${file.name}`
      const fileType = getFileType(file.name)
      let result = null;
      // 判断文件是否超过 100mb,如果超过则应用分片上传,否则应用简略上传
      if (file.size / 1024 / 1024 > 100) {console.log('分片上传')
        // 分片上传,默认分片 1Mb,如果想更改,请参考:https://help.aliyun.com/document_detail/383952.html
        result = await ossClient.multipartUpload(filePath, file, {progress: async (percent) => {onProgress({percent: percent * 100})
          },
        }).catch((error) => {onError(error)
          reject(error)
        })
      } else {console.log('简略上传')
        // 简略上传
        result = await ossClient.put(filePath, file, {progress: async (percent) => {onProgress({percent: percent * 100})
          },
        }).catch((error) => {onError(error)
          reject(error)
        })
      }
      await uploadFileCallback(result, {
        file,
        filePath,
        fileType
      }, (res) => {onSuccess(res)
        resolve(result)
      })
    })
  }

  async function uploadFileCallback(result, data, callback) {const ossPath = result.res.requestUrls[0].split('?')[0]
    const url = ossPath.replace(/^http:\/\//i, 'https://')
    const newFileRes = {
      status: result?.res?.status,
      name: result?.name,
      url: url,
    }
    // 上传胜利之后往后台数据库插入一条文件数据
    await dispatch(addFile({
      fileName: data.file.name,
      filePath: data.filePath,
      fileSize: data.file.size,
      fileContentType: data.fileType,
      categoryId: query.cid,
    }))
    callback(newFileRes)
  }


...
<Upload
  beforeUpload={beforeUploadFile}
  customRequest={uploadFileToOss}
  showUploadList={false}
  withCredentials={true}
  disabled={btnUploadDisabled}
  onChange={onUploadFileChange}>
  <Button icon={<CloudUploadOutlined/>} disabled={btnUploadDisabled}> 上传文件 </Button>
</Upload>

beforeUploadFile()办法是在上传文件之前做本人的业务逻辑解决,比方我这里的超过 500mb 的文件不容许上传

uploadFileToOss()Upload 组件自定义上传规定,所以你不必设置 action 等属性

onUploadFileChange()办法是上传文件时的变动回调,能够通过这个办法设置显示文件上传动静

下载文件(批量下载)

下载文件跟上传差不多,上面示例

function onDownload(d) {if (selectedRowKeys.length <= 0) {message.warning('请先抉择文件');
    } else {console.log('selectedRowKeys=', selectedRowKeys)

      const filterFiles = files.filter(item => selectedRowKeys.includes(item.id))
      console.log('filterFiles=', filterFiles)
      filterFiles.forEach(item => {
        const fileName = item.name
        const response = {'content-disposition': `attachment; filename=${encodeURIComponent(fileName)}`
        }
        // 填写 Object 残缺门路。Object 残缺门路中不能蕴含 Bucket 名称。const url = ossClient.signatureUrl(item.path, {response});
        const iframe = document.createElement('iframe');
        iframe.style.display = 'none';
        iframe.style.height = 0;
        iframe.src = url;
        // 与前两种形式不同,iframe 须要挂载到页面上能力触发申请
        document.body.appendChild(iframe);
        setTimeout(() => {iframe.remove();
        }, 1000);
      })
    }
  }

阐明:selectedRowKeys是我的文件列表抉择的文件 ids 汇合
item.path 是文件在 oss 的残缺门路,留神:不蕴含 host 和 bucket-name,如:a/b/c.txt

总结

1、阿里云 oss 上传文件一开始我应用的是 java sdk 上传,发现不能在 web 端分片,于是应用了 ali-oss 组件包在浏览器端上传
2、要配置 ram 权限以及获取 sts token 还有跨域

援用

js 实现单个文件下载,批量下载多个文件
async/await 捕捉谬误 捕捉 catch
OSS + Ant Design Upload 网页直传
OSS 文档:预览或下载文件
OSS 文档

退出移动版