上一篇我们对服务端和阿里云oss的配置及前端调用做了简单的介绍,但是一直报错。最终判断是文件格式问题,通常我们在reactnative中用formData上传,

formData.append('file', {
    uri: file, name: nameType(type), type: 'multipart/form-data'
  });

这里的file是文件的本地路径,如"file://android_asset/文件名",这里注意file://在安卓选择后并没有,需要我们来进行添加。但事实证明这里并不能直接通过路径上传,而是需要对文件进行处理,转为二进制数据,我们这里选择的是'rn-fetch-blob'库。选择这个库的原因有两个,一是blob比ArrayBuffer存储的二进制数据更大比较适合不定大小的文件对象,而是我们采用的网络请求库 axios或者fetch在请求大文件时不是特别稳定,因此RNFetchBlob.fetch将是更好的选择。

Blob 与 ArrayBuffer的区别

  • Blob和ArrayBuffer都能存储二进制数据。Blob相对而言储存的二进制数据大(如File文件对象)。
  • ArrayBuffer对象表示原始的二进制数据缓冲区,即在内存中分配指定大小的二进制缓冲区(容器),用于存储各种类型化数组的数据,是最基础的原始数据容器,无法直接读取或写入, 需要通过具体视图来读取或写入,即TypedArray对象或DataView对象对内存大小进行读取或写入;Blob对象表示一个不可变、原始数据的类文件对象。
  • ArrayBuffer 是存在内存中的,可以直接操作。而 Blob 可以位于磁盘、高速缓存内存和其他不可用的位置。

 通过比较我们确定了文件格式,那么接下来上代码。

export const uploadFileToOSS = async (
  files: Array<string>,
  type: string,
): Promise<any[]> => {
  const ossConfig = await globalStore.getOssConfig();
  let saveFiles: any[] = [];
  rootStore.globalIndicator.changeStatus(true)

  for (const fileOne of files) {
    try {
      const filePath = `${ossConfig.dir}${Date.now()}_${nameType(type)}`;
      let fileLength = 0;

      const fileConfigs = [
        { name: 'policy', data: ossConfig.policy },
        { name: 'x-oss-signature', data: ossConfig.signature },
        { name: 'x-oss-signature-version', data: ossConfig.version },
        { name: 'x-oss-credential', data: ossConfig.x_oss_credential },
        { name: 'x-oss-date', data: ossConfig.x_oss_date },
        { name: 'x-oss-security-token', data: ossConfig.security_token },
        { name: 'key', data: filePath },
        { name: 'success_action_status', data: '200' },
        {
          name: 'file',
          filename: nameType(type),
          data: RNFetchBlob.wrap(fileOne)
        }
      ];

      const res = await RNFetchBlob.fetch(
        'POST',
        ossConfig.host,
        { 'Content-Type': 'multipart/form-data;' },
        fileConfigs
      ).uploadProgress((written, total) => {
        fileLength = total;
        const progress = Math.round((written / total) * 100);
        console.log(`已上传: ${progress}%`);
      });

      if (res?.info().status === 200) {
        const fileName = fileOne.substring(fileOne.lastIndexOf('/') + 1) || nameType(type);
        const params = {
          fileDir: ossConfig.dir,
          fileLength,
          fileName,
          filePath,
          mimeType: mimeType(type)
        };
        const result = await globalStore.saveUploadFile(params);
        console.log("result.data>", result.data);

        if (result.success) {
          saveFiles.push(result.data);
        }
      }
    } catch (error) {
      console.error('上传失败:', error);
      xmToast.fail('上传失败,请重试');
    }
  }
  rootStore.globalIndicator.changeStatus(false)

  return saveFiles;
};

此处强调几点注意事项:

1、rootStore.globalIndicator.changeStatus(true) 这是我写的一个全局的加载loading,可直接忽略,用自己的即可。

2、阿里云oss上传成功后,没有回调。

我们需要拼接出文件地址,我代码中是这样的。

`${ossConfig.host}}${ossConfig.dir}${Date.now()}_${nameType(type)}`

最终是这样的  http://xmgj2025-test.oss-cn-hongkong.aliyuncs.com/424234324_img.png

3、阿里云oss上传后的文件地址不能直接打开查看,而是直接下载了 。

这就造成了很大的不便。因此我们通过保存文件到我们的后端,由后端下载后通过我们的服务地址来预览,这样便可完美解决不能直接预览的问题了。

4、代码中我适配了同时上传多个文件,用到了循环,切记!!这里需要循环上传文件到oss,并且在上传后要掉接口保存文件到后端服务器,for循环不会等待异步完成,与我们的需要不否,因此我采用了for of 进行顺序上传。当然你也可以用map。

好了,通过上面的代码,我们已经可以顺利的上传文件到阿里云oss服务器了!

欢迎各位猿友提问,如果觉得写的不错,请留下你的赞哦!

 

 

 

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐