react-native项目通过华为OBS预签名url实现前端直传

react-native项目通过华为OBS预签名url实现前端直传

后端具体实现参照官方链接:https://support.huaweicloud.com/bestpractice-obs/obs_05_1203.html

抱歉我实在是找不到华为obs预签名url前端直传的demo,自己搞了老半天,而且rn和js的调用方式还有区别,真是搞死人,在这里我给广大前端开发者出一个例子,减轻一些负担

下面是前端实现的一个util

javascript 复制代码
import toast from './toast';
import {Alert} from 'react-native';
import request from './request';

/**
 * 获取预签名url
 * @param param0
 * @returns
 */
const getPresignedUrlForOBS = ({
  fileName,
  mimeType,
}: {
  fileName: string;
  mimeType: string;
}) => {
  return request({
    url: `/file/getObsUrl?fileName=${fileName}`,
    method: 'GET',
  });
};

/**
 * 文件上传到obs
 * @param param0
 * @returns
 */
const uploadFile = async (file: {
  uri: string;
  type: string;
  fileName: string;
}) => {
  const {uri, type, fileName} = file;

  try {
    // 1. 获取预签名 URL(使用 text 流程验证过的接口)
    const presignedRes: any = await getPresignedUrlForOBS({
      fileName: fileName || 'image.jpg',
      mimeType: type || 'image/jpeg',
    });

    if (presignedRes.code !== 200) {
      toast(presignedRes.msg || '获取签名失败');
      return;
    }

    const signedUrl = presignedRes.data.signedUrl;
    console.log('Signed URL:', signedUrl);

    // 2. 关键:使用 fetch 读取本地图片为 Blob
    let blob;
    try {
      const response = await fetch(uri);
      blob = await response.blob();

      // 加强验证:确保读到了数据
      if (blob.size === 0) {
        throw new Error('文件读取为空,请检查 uri 是否有效');
      }
      console.log('成功读取图片 Blob,大小:', blob.size, '类型:', blob.type);
    } catch (readError) {
      console.error('读取本地文件失败:', readError);
      throw new Error(`无法读取图片文件,请重试。路径: ${uri}`);
    }

    // 3. 准备请求头(使用签名时的 Content-Type)
    const headers = {
      'Content-Type': type || 'image/jpeg',
      // 如果后端返回了其他签名头(如 x-obs-*),可合并
      ...presignedRes.data.actualSignedRequestHeaders,
    };

    // 4. 使用 fetch 上传(推荐,比 axios 更稳定)
    const uploadResponse = await fetch(signedUrl, {
      method: 'PUT',
      headers,
      body: blob, // 真正的二进制数据
    });

    if (!uploadResponse.ok) {
      const errorText = await uploadResponse.text();
      console.error('Upload failed:', errorText);
      throw new Error(`上传失败: ${uploadResponse.status} ${errorText}`);
    }

    console.log('图片上传成功!状态:', uploadResponse.status);

    // 5. 返回成功结果
    return signedUrl.split('?')[0];
  } catch (e) {
    Alert.alert('上传失败', `${fileName} 上传失败,请重试。`);
    console.error('OBS Upload Error:', e);
    return '';
  }
};

// 测试预签名 PUT是否可用
const testTextUpload = async () => {
  const text =
    'Hello from OBS test!\nThis is a simple text upload.\nTime: ' +
    new Date().toISOString();
  const fileName = 'test.txt';
  const contentType = 'text/plain'; // 关键:文本类型

  try {
    // 1. 请求后端获取预签名 PUT URL
    const presignedRes: any = await getPresignedUrlForOBS({
      fileName,
      mimeType: contentType,
    });

    const signedUrl = presignedRes.data.signedUrl;
    console.log('获取预签名URL:', signedUrl);

    // 2. 使用 PUT 上传纯文本
    const uploadRes = await fetch(signedUrl, {
      method: 'PUT',
      headers: {
        'Content-Type': contentType,
        ...presignedRes.data.actualSignedRequestHeaders,
      },
      body: text, // 直接传字符串!
    });

    console.log('uploadRes', uploadRes);
  } catch (error: any) {
    console.error('上传异常:', error);
    Alert.alert('错误', error.message || '未知错误');
  }
};

export {uploadFile, testTextUpload};
相关推荐
郭老二7 小时前
【前端】vue3:编译步骤
前端
不在逃避q7 小时前
Trae/Vs Code/Cursor命令行无法跑npm命令
前端·arcgis·npm
夏殇之殁8 小时前
包中创建自定义列表项。 . 使用自定义列表项进行数据绑定 . 将天气预报数据保存到本地内存表,通过LiveBindings进行显示。 ...
服务器·前端·javascript
The Chosen One9858 小时前
高进度算法模板速记(待完善)
java·前端·算法
陈随易8 小时前
MoonBit抓包模块pcap,查看电脑的每一次联网通信
前端·后端·程序员
FF2501_940228589 小时前
HarmonyOS应用开发实战:猫猫大作战-在排行榜和历史记录查询中,排序是必不可少的操作【apple_product_name】
华为·harmonyos·鸿蒙
新中地GIS开发老师9 小时前
WebGIS开发学生作品|低空航天管理与航线规划系统
前端·javascript·webgis·三维gis开发
用户059540174469 小时前
大模型对话记忆持久化踩坑实录:用 Playwright 自动化测了 300 次,终于揪出会话丢失的真凶
前端·css
丙氨酸長鏈9 小时前
Web前端入门第 问:JavaScript 一个简单的 IndexedDB 数据库入门示例
前端·javascript·数据库
kyriewen10 小时前
面试官让我手写虚拟列表——AI生成的版本,快速滚动几下就白屏了
前端·javascript·面试