上一篇我们对服务端和阿里云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服务器了!
欢迎各位猿友提问,如果觉得写的不错,请留下你的赞哦!