- 支持固定ak,sk,异步获取固定ak,sk或者临时ak,sk,token
- 临时token,未过期不重新获取,过期前自动重新获取。
- vod 上传
- vod 详情获取重试机制
- 基于nanoId 生成上传key,可自定义key
npm install obs-upload -Simport ObsUpload from 'obs-upload'如果你需要华为sdk原本的 ObsClient
import { ObsClient } from 'obs-upload'const { default: ObsUpload, ObsClient } = require('obs-upload');const obsUpload = new ObsUpload(initOptions, initConfig){ // 可选 ak: '', // 可选 sk: '', // 可选 // https://developer.huaweicloud.com/endpoint?OBS server: 'obs.cn-east-2.myhuaweicloud.com', // 可选 bucketName: '', // 异步获取ak,sk。 getAuthorization(options) { return new Promise((resolve, reject) => { http.post('https://xxx.com/api/getObsToken').then(res => { let resData = res.data.data // resolve 时接收以下字段。 resolve({ // 可以是临时ak,也可是是固定ak ak: resData.ak, // 可以是临时sk,也可以是固定sk sk: resData.sk, // 可选;如果是临时秘钥,此参数必传 securityToken: resData.securityToken, // https://developer.huaweicloud.com/endpoint?OBS // 如果上边传了,此处不必传。优先使用此值 // server: resData.endPoint, // 如果上边传了,此处不必传。优先使用此值 // bucketName: resData.bucketName, // 可选;token 存活时间,相对时间,单位秒。非必传。如果securityToken 过期,则会重新调用getAuthorization 获取临时秘钥token 等参数。比如token 存活时间5分钟,则此值为 300(5*60)。如果不传且为临时秘钥,则每次上传都会重新获取securityToken; 如何expireSeconds 为0,则表示ak,sk 永久有效,不会重新获取。如果ak,sk 为固定秘钥,则expireSeconds 应接收0,表示永久有效。 expireSeconds: resData.durationSeconds }) }).catch(err => { // 失败时只接受Error 对象 reject(err) }) }) } }{ // 过期时间冗余。单位ms.如果原本token 20s后过期,此值让token,提前10s过期; expireRedundancy: 10 * 1000, /** * 分段策略。按照min从大到小排列。 * min: Number 类型,单位kb,当前文件的size大于等于当前min,则使用该策略 * concurrentNum: 段上传时的并发数。 * 如果当前文件的size 大于等于partsStrategy 的最后一个策略的min,则使用分段上传,否则直接上传。如果partsStrategy不存在,或者为空数组,则所有文件都直接上传,不使用分段上传。 * */ partsStrategy: [ { min: mToSize(1024), // 单位kb partSize: mToSize(20), // 每段大小 concurrentNum: 10 // 并发数 }, { min: mToSize(512), partSize: mToSize(20), concurrentNum: 10 // 并发数 }, { min: mToSize(200), partSize: mToSize(15), concurrentNum: 10 // 并发数 }, { min: mToSize(100), partSize: mToSize(10), concurrentNum: 10 // 并发数 } ], // 检测是否为视频方法。用户自定义检测方法。返回 Boolean 类型。 checkIsVideo(file) { let fileType = file.type return fileType.startsWith('video/') }, // 是否将视频上传vod videoToVod: false, // 是否需要视频时长,单位s, 可能有2位小数,也有可能有3位小数 needVideoDuration: false, // 通知obs 转存vod。需要返回vodId // apiObsToVod (file, data) { // // }, // 是否需要vod 的播放地址。如果为false,则在apiObsToVod 返回vodId 时响应成功。否则继续调用apiVodDetails 获取vod 详情 needVodURL: false, // 查询vod 详情,需要返回url。因为vod 转码是异步的,可能obs已经转存vod,但是转码中,此时获取不到vod 的播放url。 // apiVodDetails (vodId, data) { // // }, // 查询vod 详情失败时,重试次数; 0为无限次,直到查询到url,才会停止查询。 vodTimesLimit: 0, // 重试查询vod视频详情时时间间隔,单位ms。也可以是一个函数。 vodTimeInterval: 1000, // 可直接返回key,也可返回一个promise,接收key // getUploadKey (file, other, nanoId, fileType) { // // } }apiObsToVod
// 该接口作用主要告知后端,需要把当前视频转存到vod,仅在成功上传obs后调用一次 /*** https://support.huaweicloud.com/api-vod/vod_04_0201.html https://support.huaweicloud.com/api-vod/vod_04_0051.html */ apiObsToVod(file, data) { return new Promise((resolve, reject) => { const videoType = file.type.split('/')[1] // 获取媒资Id http.post('https://xxx.com/api/getAssetId', { object: data.key, title: file.name, videoType: videoType.toUpperCase() }).then(res => { let {code, msg, data} = res.data if (code === "200" && data) { console.log(data); // 成功时必须接返回下参数 resolve({ data: { // vodId vodId: data, // 必传 // 该视频在vod 的播放地址 // url: data.url // 非必传 }, // 需要携带的自定义参数。上传成功后 obs_upload_vod_data 字段体现。 otherData: data }) } else { // 内部判断 data.vodId 不存在,则认定上传失败。msg 可传可不传,表示上传失败时 error.message 。 resolve({ data: data, msg: msg }) } }).catch(err => { // 如果接收 reject 则会判断上传失败。注意reject 应始终只接收一个Error 对象 reject(err) }) }) }apiVodDetails
// 该接口作用主要获取视频vod播放地址。因为obs 转存vod 不是同步的,在apiObsToVod 时可能获取不到vod 的播放地址,所以通过此接口尝试多次。在 ‘needVodURL’ 为true 时调用。会尝试 config.vodTimesLimit 次。如果尝试config.vodTimesLimit次后仍获取不到url,则判定上传失败。如果needVodURL 不为true 则不需要提供此参数。 // https://support.huaweicloud.com/api-vod/vod_04_0202.html apiVodDetails(vodId, data) { return new Promise((resolve, reject) => { http.post(`https://xxx.com/api/getAssetDetail`, {assetId: vodId}).then(res => { let {code, msg, data} = res.data // https://support.huaweicloud.com/api-vod/vod_04_0202.html // 截图失败,不再重试 //if (data && data.thumbnailStatus === 'THUMBNAIL_FAILED') { // reject(new Error('截图失败')) // return //} if (code === "200" && data) { // 成功时必须接返回下参数 resolve({ data: { // 该视频在vod 的播放地址。获取到url 后会立即停止重试。 url: data.videoUrl // 非必传 }, // 需要携带的自定义参数。上传成功后 obs_upload_vod_details 字段体现。 otherData: data, msg: msg }) } else { // 当前还没有url,会继续进行重试。 resolve({ data: data, otherData: data, msg: msg // msg 可传可不传,表示上传失败时 error.message 。 }) } }).catch(err => { // 如果接收 reject 则会停止重试。注意reject 应始终只接收一个Error 对象 reject(err) }) }) }vodTimeInterval
重试查询vod视频详情时时间间隔,单位ms。也可以是一个函数。
/** * file * data { * key, * bucketName, * server, * obsURL, * vodId * } * */ vodTimeInterval(file, data) { const mToSize = (num) => { return num * 1024 * 1024 } const fileSize = file.size if (fileSize > mToSize(300)) { return 3 * 1000 } else if (fileSize > mToSize(200)) { return 2 * 1000 } else { return 1000 } }getUploadKey
自定义上传文件key
返回上传的文件key。可使用普通函数 或者Promise.
/** * @param file - file 文件 * @param {Object} other - upload 传的第二个参数 * @param {Function} nanoId - nanoid 唯一id 生成函数 * @param {String} fileType - 文件后缀,带. 例如:.png .mp4 * @return {String} 上传文件的key * */ getUploadKey(file, other, nanoId, fileType) { return new Promise(resolve => { setTimeout(() => { resolve(`${other.folderPath}2022-06-18/${nanoId()}/${Date.now()}${fileType}`) }, 1500) }) }注意:不建议文件路径中出现中文或者特殊字符;可考虑使用 encodeURIComponent 处理
obsUpload.upload({ // 必传;file 对象 file: file, // 成功触发;可选; onSuccess (result) { }, // 上传进度更新;可选; onProgress (data) { }, // 上传失败。可选;error Error 对象 onError (error) { } }, { // 上传文件的文件夹路径;非必传 folderPath: 'test/' })upload返回一个Promise
obsUpload.upload({file}).then().catch()获取client 实例,Promise
obsUpload.getClient().then(obsClient => { }).catch()当前obsUpload 实例的 obsClient。不存在时为null.
obsUpload.obsClient当前插件的版本号
obsUpload.VERSION