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};
相关推荐
前端大卫2 小时前
Vue3 + Element-Plus 自定义虚拟表格滚动实现方案【附源码】
前端
却尘2 小时前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare2 小时前
浅浅看一下设计模式
前端
Lee川2 小时前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix2 小时前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人2 小时前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl2 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人3 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼3 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端