记录一下华为OBS文件上传(前端部分)

1,144 阅读1分钟

版本:

"esdk-obs-browserjs": "^3.22.3"

一次性上传

import { Message } from 'element-ui'
import ObsClient from 'esdk-obs-browserjs/src/obs'
function obsUpload() {
    return async function(file) {
        const _type = file.file.type
        const {
            code,
            data: obsData
        } = await ossGenerate() // 从后端接口获取文件上传所需要的参数
        if (code !== 0) {
            Message({
                message: '获取obs参数失败',
                type: 'error',
                duration: 5 * 1000
            })
        }
        const _obs = obsData
        const callback = (transferredAmount, totalAmount) => {
            // 获取上传进度百分比
            file.file.percent = parseFloat(transferredAmount * 100.0 / totalAmount).toFixed(2);
            file.onProgress(file.file)
        };
        const client = new ObsClient({
            server: _obs.endpoint, // 服务终端节点
            access_key_id: _obs.access_key_id, // 访问密钥id
            secret_access_key: _obs.access_key_secret, // 访问密钥
            security_token: _obs.security_token
        });
        client.putObject({
            Bucket: _obs.bucket, // 桶名
            Key: _obs.object_key, // 文件名
            SourceFile: file.file, //流文件
            ProgressCallback: callback
        }, (err) => {
            if (err) {
                Message({
                    message: '失败',
                    type: 'error',
                    duration: 5 * 1000
                })
            } else {
                // 上传后文件URL: https://桶名.域名/文件夹目录层级/对象名
                let url = 'https://' + _obs.bucket + '.' + _obs.endpoint.slice(8) + '/' + _obs.object_key;
                file.file.url = url;
                file.onSuccess(file.file);
            }
        })
    }
}

分段上传

import ObsClient from 'esdk-obs-browserjs/src/obs'
import { Message } from 'element-ui'
import { bus } from '@/bus'

// 初始化分段上传任务(获取UploadId)
function initiateMultipartUpload (client, _obs) {
  return new Promise((resolve, reject) => {
    client.initiateMultipartUpload({
      Bucket: _obs.bucket, // 桶名
      Key: _obs.object_key, // 文件名
      ContentType: 'text/plain',
      // Metadata: { 'property': 'property-value' }
    }, function (err, result) {
      if (err) {
        Message({
          message: '获取 UploadId 失败',
          type: 'error',
          duration: 5 * 1000
        })
      } else {
        if (result.CommonMsg.Status < 300 && result.InterfaceResult) {
          sessionStorage.setItem(`${_obs.object_key}_UploadId`,result.InterfaceResult.UploadId)
          resolve(result.InterfaceResult.UploadId)
        }
      }
    });
  })
}

// 上传段
function obsUploadPart (client, _obs, file) {
  return new Promise(async (resolve, reject) => {

    let Parts = [];
    let UploadId = sessionStorage.getItem(`${_obs.object_key}_UploadId`);
    if (!UploadId) {
       UploadId = await initiateMultipartUpload(client, _obs);
    }
    const PartSize = 50 * 1024 * 1024;
    const lastPartSize = file.size % PartSize;
    // 段数量
    const count = Math.ceil(file.size / PartSize);
    // 上传第n段
    const uploadPart = (n) => {
      client.uploadPart({
        Bucket: _obs.bucket,
        Key: _obs.object_key, 
        PartNumber: n, // 设置分段号,范围是1~10000
        UploadId, // 设置Upload ID
        SourceFile: file, // 设置将要上传的大文件
        PartSize: count === n ? lastPartSize : PartSize, // 设置分段大小
        Offset: (n - 1) * PartSize, // 设置分段的起始偏移大小
        ProgressCallback: function (tfa, ta) {
          // 进度条
          let percentage = ((tfa + ta * (n - 1)) * 100.0 / (ta * count)).toFixed(2);
          bus.$emit('percentage', percentage);
        },
      }, function (err, result) {
          if (result.CommonMsg.Status < 300 && result.InterfaceResult) {
             Parts.push({
               PartNumber: n,
               ETag: result.InterfaceResult.ETag
             });
            
             count === n ? resolve({ UploadId, Parts }) : uploadPart(n + 1);
          } else { // 失败重传
             uploadPart(n);
          }
      });
    }

    // 上传第1段
    uploadPart(1);
  })
}


// 合并分段
async function obsMultipartUpload (_obs, file) {
  return new Promise(async (resolve, reject) => {
    // 创建ObsClient实例
    const obsClient = new ObsClient({
      server: _obs.endpoint,
      access_key_id: _obs.access_key_id,
      secret_access_key: _obs.access_key_secret,
      security_token: _obs.security_token
    });

    const { UploadId, Parts } = await obsUploadPart(obsClient, _obs, file);
    obsClient.completeMultipartUpload({
      Bucket: _obs.bucket, // 桶名
      Key: _obs.object_key, // 文件名
      UploadId, // 设置Upload ID
      Parts // 所有有效的分段(分段号、分段ETag值)
    }, function (err, result) {
      if (err) {
        Message({
          message: '合并文件段失败',
          type: 'error',
          duration: 5 * 1000
        })
        reject(err);
      } else {
        sessionStorage.removeItem(`${_obs.object_key}_UploadId`);
        resolve(result.CommonMsg.Status);
      }
    });
  })
}

export default obsMultipartUpload;

调用

import obsMultipartUpload from "@/utils/obsUpload";
obsMultipartUpload(_obs, file).then((res) => {
     ...// 上传成功操作
}).catch(err => {
     ...// 上传失败操作
})