使用过程
使用PUT方式的签名URL上传文件的过程如下:
代码示例
- 文件拥有者生成PUT方法的签名URL
const OSS = require("ali-oss");// 获取签名URL
const client = await new OSS({accessKeyId: 'yourAccessKeyId',accessKeySecret: 'yourAccessKeySecret',bucket: 'examplebucket',region: 'oss-cn-hangzhou',authorizationV4: true
});/*** 获得一个客户端文件上传密钥* @see https://help.aliyun.com/zh/oss/developer-reference/authorized-access-3?spm=a2c4g.11186623.0.0.7753743e1DG5BH** @param {object} params* @param {string} [params.extension] - 文件后缀,带`.`* @param {string} [params.mimeType] - 文件 mimeType* @param {object} [params.headers = {}] - 头部* @param {string} [params.filename] - 文件名 会设置 `Content-Disposition` 默认为 inline 类型* @param {object} [params.meta] - meta 属性* @param {string} [params.dir] - dir 上传文件目录* @param {object} [params.cache = '1y'] - 缓存时间 默认一年* @returns {Promise<{ url: string, headers: {[key of string]: string}, method: string; }>}*/
async function getClientUploadSecret(params = {}) {params = {cache: '1y',dir: '',headers: {},...params,};if (params.dir.length > 0 && !params.dir.endsWith('/')) params.dir = `${params.dir}/`;params.dir = normalizePath(params.dir);/*** 文件后缀* @type {string|undefined}*/let ext;if (params.extension) {ext = params.extension;} else if (params.mimeType) {ext = mimeType.extension(params.mimeType);}if (!ext && params.filename) {ext = path.extname(params.filename);}if (!isEmpty(ext)) ext = ext.toLowerCase();// console.log('ALI BUCKET: ', ALIYUN_CONFIG.oss.bucket, params);// 根据新的bucket规整文件夹分类 /image /video /audiologger.info('getClientUploadSecret', ext, getFileBucketSaveUrl(ext), params, new Date().getTime()+3600*1000);// 生成文件的签名URLlet signatureUrl = store.signatureUrl(`clouddriver/${getFileBucketSaveUrl(ext)}/${nanoid()}${ext || ''}`, {method: 'PUT',// expires: new Date().getTime()+3600*1000, // 过期时间:1h后'Content-Type': params.mimeType || mimeType.contentType(ext) || 'application/octet-stream',});// 头const headers = {'Content-Type': params.mimeType || mimeType.contentType(ext) || 'application/octet-stream',};if (params.filename) {headers['Content-Disposition'] = contentDisposition(params.filename, { fallback: false, type: 'inline' });}if (params.meta) {const meta = _.mapKeys(params.meta, (_, key) => `x-oss-meta-${key}`);_.defaults(headers, meta);}if (params.cache) {const cache = sec(params.cache);headers['Cache-Control'] = `public, max-age=${cache}, immutable`;headers['Expires'] = moment().add(cache, 's').toDate().toGMTString();}const url = signatureUrl.split('https:') && signatureUrl.split('https:').length ? signatureUrl.split('https:')[1] : signatureUrl;return {url,method: 'PUT',headers};
}
- 最后返回给前端这些数据,前端通过 PUT 将文件上传到此 url 即可
{"url": "//xxxxxx-courseware-av-test.oss-cn-beijing.aliyuncs.com/clouddriver/video/khue2VxS15XO7SdHfcbjR.mp4?OSSAccessKeyId=LTAI5tLMMDPtxJ93qZN31sfg&Expires=1737445832&Signature=ar5%2BbAkYmJWiFu%2FVMhEGAivP%2BDg%3D","method": "PUT","headers": {"Content-Type": "video/mp4","Content-Disposition": "inline; filename*=UTF-8''1%E6%B5%8B%E8%AF%95%E8%A6%86%E7%9B%96.mp4","Cache-Control": "public, max-age=31557600, immutable","Expires": "Wed, 21 Jan 2026 13:20:31 GMT"}
}
- 前端通过接口拿到上面url数据,然后做PUT请求,service.getUploadInfo 就是获取url的接口了
/*** 获取文件上传的路径等头信息* @param {File} file
*/getUploadInfo = async(file) => {const query = {cache: '1y',filename: file.name};let res = await service.getUploadInfo(query);res.url = 'https:' + res.url;return res;
};
-
上传的动作
/*** 上传的动作* @param {Object} */_upload =({ fileRecord, successCallback, progressCallback, errorCallback }) => {const { file: File, method, url, headers } = fileRecord;// XMLHttpRequest 对象const xhr = new XMLHttpRequest();xhr.open(method, url, true);for (let key in headers) {xhr.setRequestHeader(key, headers[key]);};if (common.getIsClient()) {const token = new URLSearchParams(history.location.search).get('token');xhr.setRequestHeader('x-roombox-token', token);}// 这三个是上传的一些回调xhr.onload = successCallback.bind(this, fileRecord);xhr.upload.onprogress = progressCallback.bind(this, fileRecord);xhr.onerror = errorCallback.bind(this, fileRecord);xhr.send(File);return xhr;
};