突破测试环境文件上传带宽瓶颈!React Native 阿里云 OSS 直传文件格式问题攻克一

前言

通常情况下,作为前后端分离的项目来说,文件上传是最寻常的功能之一。虽然每个公司选择的文件管理云库各不相同,但实现思路基本一致。我所在公司使用阿里云oss文件管理,之前服务端做了透传,但是由于每个测试环境的带宽限制,导致在测试环境出现文件上传受限的问题。因此,痛定思痛,决定抛开中间层,直传阿里云OSS。

上干货

根据终端不同,阿里云oss官方文档提供了多种直传方式。

1、web端直传

2、移动应用端直传

3、小程序直传

4、鸿蒙直传

由于react-native是跨平台框架,又是通过js编写的,因此可供选择的有web端直传移动应用端直传 。但是对于很多RN开发者并不具备很强的原生开发能力,而且还需要引入OSS Android SDK,OSS iOS SDK,如果同时开发鸿蒙的话还需要引入OSS Harmony SDK,这样不但维护成本高,开发周期也会增加,况且不利于维护。因此web端直传成为唯一可供选择,并且是最具完美的直传方式。

根据官网实践例子,一步一步进行。

服务端配置

您可以使用PostObject接口,将文件直接从 Web 端上传到 OSS,服务器生成的签名为直传操作提供安全保障,同时支持配置上传策略(Policy)以限制上传操作并满足业务需求。

实现服务端签名直传,只需3步:

说明 由于使用了临时访问凭证,整个过程中不会泄露业务服务器的长期密钥,保证了文件上传的安全性。

  1. 配置OSS :在控制台创建一个Bucket,用于存储用户上传的文件。同时,为 Bucket 配置跨域资源共享(CORS) 规则,以允许来自 Web 端的跨域请求。

  2. 配置服务端: 调用STS服务获取一个临时访问凭证,然后使用临时访问凭证和服务端预设的上传策略Policy(如Bucket名称、目录路径、过期时间等)生成签名授权用户在一定时间内进行文件上传。

    XML 复制代码
    {
      "Version": "1",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "oss:PutObject",
          "Resource": "acs:oss:*:*:<Bucket名称>/*"
        }
      ]
    }

  3. 配置Web端:构造HTML表单请求,通过表单提交使用签名将文件上传到OSS。

前端上传接口所需的oss配置参数,后端需要提供业务接口来提供,接收到所有必需的配置信息后,就可以请求上传了。此请求将直接与OSS服务进行通信,从而实现文件的上传。以下字段需要后端通过接口提供,至于后端如何获取,请参考服务端签名及参数组装

客户端实现

根据官网给的web端例子,在ReactNative下是否可以直接使用呢?答案是否定的!

web端例子

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>服务端生成签名上传文件到OSS</title>
</head>
<body>
<div class="container">
    <form>
        <div class="mb-3">
            <label for="file" class="form-label">选择文件:</label>
            <input type="file" class="form-control" id="file" name="file" required />
        </div>
        <button type="submit" class="btn btn-primary">上传</button>
    </form>
</div>

<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
    const form = document.querySelector("form");
    const fileInput = document.querySelector("#file");

    form.addEventListener("submit", (event) => {
        event.preventDefault();

        const file = fileInput.files[0];

        if (!file) {
            alert('请选择一个文件再上传。');
            return;
        }

        const filename = file.name;

        fetch("/get_post_signature_for_oss_upload", { method: "GET" })
            .then((response) => {
                if (!response.ok) {
                    throw new Error("获取签名失败");
                }
                return response.json();
            })
            .then((data) => {
                let formData = new FormData();
                formData.append("success_action_status", "200");
                formData.append("policy", data.policy);
                formData.append("x-oss-signature", data.signature);
                formData.append("x-oss-signature-version", "OSS4-HMAC-SHA256");
                formData.append("x-oss-credential", data.x_oss_credential);
                formData.append("x-oss-date", data.x_oss_date);
                formData.append("key", data.dir + file.name); // 文件名
                formData.append("x-oss-security-token", data.security_token);
                formData.append("file", file); // file 必须为最后一个表单域

                return fetch(data.host, { 
                    method: "POST",
                    body: formData
                });
            })
            .then((response) => {
                if (response.ok) {
                    console.log("上传成功");
                    alert("文件已上传");
                } else {
                    console.log("上传失败", response);
                    alert("上传失败,请稍后再试");
                }
            })
            .catch((error) => {
                console.error("发生错误:", error);
            });
    });
});
</script>
</body>
</html>

react-native中实现

javascript 复制代码
// 多媒体类型
export const nameType = (type: string) => {
  switch (type) {
    case 'image':
      return 'image.png';
    case 'video':
      return `video.mp4`;
    case 'voice':
      return 'voice.wav';
    default:
      return 'image.png';
  }
};

export const uploadFileToOSS = async function (
  file: string,
  type: string,
  config?: AxiosRequestConfig) {
  const ossConfig = await getOssConfig(); // 后端接口提供oss配置
  const fileName =`${ossConfig.dir}${Date.now()}_${nameType(type)}`

  const formData = new FormData();

  formData.append('success_action_status', '200');
  formData.append('policy', ossConfig.policy);
  formData.append("x-oss-signature", ossConfig.signature);
  formData.append("x-oss-signature-version", ossConfig.version);
  formData.append("x-oss-credential", ossConfig.x_oss_credential);
  formData.append("x-oss-date", ossConfig.x_oss_date);
  formData.append('key', fileName );
  formData.append("x-oss-security-token", ossConfig.security_token);
  formData.append('file', {
    uri: file, name: nameType(type), type: 'multipart/form-data'
  });

  try {
    const response = await axios({
      method: 'POST',
      url: ossConfig.host,
      data: formData,
      headers: { 'Content-Type': 'multipart/form-data' }
    });

    if (response.status == 200) {
       console.log(ossConfig.host+fileName )
    } else {
      throw new Error(`上传失败: ${response.status}`);
    }
  } catch (error) {
    if (!error.response) {
      console.error('Network Error:', error); // 如 Network Error
    } else {
      console.error('Response Error:', error.response.status, error.response.statusText, error.response);
    }
  }
}

看着似乎没什么问题,那么去运行,果不其然,报错了,而且没有太多有用的信息。起初以为是参数传错了,经过仔细检查一点没错。

这就怪了,经过反复的删减修改,怀疑是文件格式问题,当然事实也确实如此。

修改文件格式后,终于,终于看到了黎明的曙光,100M的视频瞬间上传成功后,那种喜悦涌上心头,那种手足无措后的惊喜,顿时让我忘却了几天来焦头烂额的疲惫。

好了下班了,几天没睡个好觉了,先休息了,下一篇我将详细阐述如何解决文件格式导致ReactNative中使用web端直传OSS报错的问题。

欢迎猿友们评论,提问。如果觉得写的不错点个赞再走哦!

下一篇 突破测试环境文件上传带宽瓶颈!React Native 阿里云 OSS 直传文件格式问题攻克二

相关推荐
XINVRY-FPGA15 小时前
XCVP1902-2MSEVSVA6865 Xilinx FPGA Versal Premium SoC/ASIC
嵌入式硬件·安全·阿里云·ai·fpga开发·云计算·fpga
国际云,接待15 小时前
阿里云CDN和腾讯云CDN综合对比
运维·服务器·阿里云·性能优化·云计算·腾讯云
天河归来15 小时前
通过阿里云服务发送邮件
数据库·阿里云·云计算
hnlucky15 小时前
k8s中kubeSphere的安装使用+阿里云私有镜像仓库配置完整步骤
linux·运维·学习·阿里云·容器·kubernetes·云计算
嵌入式学习菌15 小时前
mqtt协议连接阿里云平台
物联网·网络协议·阿里云·云计算
皓月盈江20 小时前
阿里云服务器SSH远程登陆输错密码次数过多导致本地IP禁止登陆,网站和Linux宝塔面板无法访问,但是网站在其他网络访问一切正常
服务器·阿里云·ssh·linux宝塔面板·输错密码次数过多·服务器禁止ip登陆·其他网络访问正常
皓月盈江2 天前
阿里云服务器采用crontab定时任务使acme.sh全自动化申请续签免费SSL证书,并部署在Linux宝塔网站和雷池WAF
服务器·阿里云·crontab·雷池waf·linux宝塔面板·acme.h·续签ssl证书
云布道师2 天前
中企出海大会|打造全球化云计算一张网,云网络助力中企出海和AI创新
网络·人工智能·阿里云·云计算·云布道师
zqh176736464693 天前
新消息!阿里云ACP大模型认证有变化!
阿里云·云计算
yours_Gabriel3 天前
【文件上传】阿里云对象存储服务实现文件上传
java·阿里云·云计算·maven