本文介绍如何在支付宝小程序环境下将文件上传到OSS。
背景信息
小程序是当下比较流行的移动应用,例如微信小程序、支付宝小程序等。它是一种全新的开发模式,无需下载和安装,为终端用户提供更优的用户体验。如何在小程序环境下上传文件到OSS也成为开发者比较关心的一个问题。
与JavaScript客户端直传实践的原理相同,小程序上传文件到OSS也是利用OSS提供的PostObject接口来实现表单文件上传到OSS。关于PostObject的详细介绍请参见PostObject。
步骤1:获取签名
为了您的数据安全,建议使用签名方式上传文件。OSS提供以下两种签名方式的代码:
服务端签名
使用服务端签名时,您需要先搭建一个签名服务,之后由客户端调用签名服务生成签名。
服务端签名源码
uploadOssHelper.js代码如下:
const crypto = require("crypto-js"); class MpUploadOssHelper { constructor(options) { this.accessKeyId = options.accessKeyId; this.accessKeySecret = options.accessKeySecret; this.timeOut = options.timeout || 1; // 限制参数的生效时间(单位:小时)。 this.maxSize = options.maxSize || 10; // 限制上传文件大小(单位:Mb)。 } createUploadParams() { const policy = this.getPolicyBase64(); const signature = this.signature(policy); return { OSSAccessKeyId: this.accessKeyId, policy: policy, signature: signature, }; } getPolicyBase64() { let date = new Date(); // 设置Policy过期时间。 date.setHours(date.getHours() + this.timeOut); let srcT = date.toISOString(); const policyText = { expiration: srcT, conditions: [ // 限制上传文件大小。 ["content-length-range", 0, this.maxSize * 1024 * 1024], ], }; const buffer = new Buffer(JSON.stringify(policyText)); return buffer.toString("base64"); } signature(policy) { return crypto.enc.Base64.stringify( crypto.HmacSHA1(policy, this.accessKeySecret) ); } } module.exports = MpUploadOssHelper;
服务端接口示例
以Express为例,接口代码如下:
const express = require('express'); const app = express(); const MpUploadOssHelper = require("./uploadOssHelper.js"); app.get('/getPostObjectParams', (req, res) => { const mpHelper = new MpUploadOssHelper({ // 填写AccessKey ID。 accessKeyId: '<Your AccessKeyId>', // 填写AccessKey Secret。 accessKeySecret: '<Your AccessKeySecret>', // 限制参数的生效时间(单位:小时)。 timeout: 1, // 限制上传文件大小(单位:Mb)。 maxSize: 10, }); // 生成参数。 const params = mpHelper.createUploadParams(); res.json(params); })
客户端签名
使用客户端签名时,您需要先在服务端搭建一个STS服务,之后由客户端获取STS临时授权账号并生成签名。
服务端搭建STS服务
const OSS = require('ali-oss') const STS = OSS.STS const express = require('express'); const app = express(); const stsClient = new STS({ // 填写您的AccessKeyID。 accessKeyId: '<Your AccessKeyId>', // 填写您的AccessKeySecret。 accessKeySecret: '<Your AccessKeySecret>', // 填写Bucket名称。 bucket: '<Your bucket name>' }); async function getToken() { // 指定角色的ARN。格式为acs:ram::$accountID:role/$roleName。 const STS_ROLE = '<STS_ROLE>' const STSpolicy = { Statement: [ { Action: ['oss:*'], Effect: 'Allow', Resource: ['acs:oss:*:*:*'] } ], Version: '1' }; const result = await stsClient.assumeRole( // 填写用于授权的RAM角色的ARN值。详情请参见查看RAM角色。 STS_ROLE, STSpolicy, // 指定STS过期时间,单位为秒。 3600 ); const { credentials } = result; return credentials; } app.get('/getToken', async (req, res) => { // 获取STS。 const credentials = await getToken() console.log(credentials.AccessKeyId) console.log(credentials.AccessKeySecret) console.log(credentials.SecurityToken) res.json(credentials); })
客户端获取STS临时账号并生成签名
import crypto from 'crypto-js'; import { Base64 } from 'js-base64'; // 计算签名。 function computeSignature(accessKeySecret, canonicalString) { return crypto.enc.Base64.stringify(crypto.HmacSHA1(canonicalString, accessKeySecret)); } const date = new Date(); date.setHours(date.getHours() + 1); const policyText = { // 设置policy过期时间。 expiration: date.toISOString(), conditions: [ // 限制上传的文件大小。 ["content-length-range", 0, 1024 * 1024 * 1024], ], }; async function getFormDataParams() { const credentials = await axios.get('/getToken') const policy = Base64.encode(JSON.stringify(policyText)) // policy必须为base64的string。 const signature = computeSignature(credentials.AccessKeySecret, policy) const formData = { OSSAccessKeyId: credentials.AccessKeyId, signature, policy, 'x-oss-security-token': credentials.SecurityToken } return formData }
步骤2:使用支付宝小程序上传
支付宝小程序上传文件参考代码如下:
const host = '<host>';
const signature = '<signatureString>';
const ossAccessKeyId = '<accessKey>';
const policy = '<policyBase64Str>';
const securityToken = '<x-oss-security-token>';
const key = '<object name>'
my.chooseImage({
chooseImage: 1,
success: res => {
const path = res.apFilePaths[0];
my.uploadFile({
url: host,
fileType: 'image',
fileName: 'file',
filePath: path,
formData: {
key,
policy,
OSSAccessKeyId: ossAccessKeyId,
signature,
success_action_status: '200',
// 使用STS签名时传入securityToken。
// 'x-oss-security-token': securityToken
},
success: (res) => {
// 将上传成功状态码设置为200,默认状态码为204。
if (res.statusCode === 200) {
console.log('上传成功');
}
my.alert({ content: 'success info: ' + res.data });
},
fail: err => {
console.log(err);
}
});
}
});
相关参数如下:
host:填写存储空间的访问域名,例如https://test.oss-cn-zhangjiakou.aliyuncs.com。若您的存储空间已绑定自定义域名,建议填写您的自定义域名。
signature:填写步骤1中获取到的signature信息。
ossAccessKeyId:填写您的AccessKey ID,若是通过STS获取的临时用户,则填写临时用户的AccessKey ID。
policy:填写步骤1中获取到的policy信息。
key:设置文件上传至OSS后的文件路径。例如需要将myphoto.jpg上传至test文件夹下,此处填写test/myphoto.jpg。
securityToken:若使用STS认证,此项填写客户端签名时获取到的SecurityToken。