抖音小程序直传OSS是指您在使用抖音小程序时,可以直接将内容(例如图片、视频等)上传至OSS,而不是先上传到小程序服务器再由服务器转发至OSS。通过抖音小程序直传的方式能够减轻服务器压力,提升上传速度和用户体验。
前提条件
准备工作
通过抖音小程序直传文件到OSS时,为确保上传请求的安全性,客户端不直接使用长期访问密钥,而是通过RAM用户扮演RAM角色的方式向STS服务发起请求获取临时访问凭证。
创建RAM用户。
登录RAM控制台。
在左侧导航栏,选择身份管理>用户。
单击创建用户。
输入登录名称和显示名称。
在访问方式区域下,选择使用永久 AccessKey 访问,然后单击确定。
根据界面提示,完成安全验证。
复制访问密钥(AccessKey ID和AccessKey Secret)。
重要RAM用户的AccessKey Secret只在创建时显示,后续不支持查看,请妥善保管。
为RAM用户授予请求AssumeRole的权限。
创建RAM用户后,您需要授予RAM用户通过扮演角色来调用STS服务的权限。
单击已创建RAM用户右侧对应的添加权限。
在新增授权页面,选择AliyunSTSAssumeRoleAccess系统策略。
单击确认新增授权。
创建RAM角色。
您需要创建RAM角色,用于定义RAM角色被扮演时,可以获得OSS服务的哪些访问权限。
在左侧导航栏,选择身份管理>角色。
单击创建角色,选择可信实体类型为阿里云账号,单击下一步。
在创建角色对话框,角色名称填写为RamOssTest,选择信任的云账号为当前云账号。
单击完成。角色创建完成后,单击关闭。
在角色页面,搜索框输入角色名称RamOssTest,然后单击RamOssTest。
单击ARN右侧的复制,保存角色的ARN。
为RAM角色授予上传文件的权限。
为RAM角色附加权限策略,明确RAM角色在被扮演时所能拥有的OSS资源访问权限。结合本实例教程,希望RAM用户在扮演该角色后只能向OSS指定Bucket上传文件,则需要为角色添加写入权限的策略。
创建上传文件的自定义权限策略。
在左侧导航栏,选择权限管理>权限策略。
在权限策略页面,单击创建权限策略。
在创建权限策略页面,单击脚本编辑,然后在策略文档输入框中赋予角色上传文件到examplebucket的权限。具体配置示例如下。
{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": [ "oss:PutObject" ], "Resource": [ "acs:oss:*:*:examplebucket/*" ] } ] }
策略配置完成后,单击继续编辑基本信息。
在基本信息区域,填写策略名称为RamTestPolicy,然后单击确定。
为RAM角色RamOssTest授予自定义权限策略。
在左侧导航栏,选择
。在角色页面,找到目标RAM角色RamOssTest。
单击RAM角色RamOssTest右侧的新增授权。
在添加权限页面下的自定义策略页签,选择已创建的自定义权限策略RamTestPolicy。
单击确定。
方案部署
修改示例工程express-douyin.zip中的
getToken.js
配置。const crypto = require("crypto-js"); const STS = require("ali-oss").STS; const { accessKeyId, secretAccessKey: accessKeySecret } = process.env; const stsClient = new STS({ // 从环境变量中获取准备工作中创建的RAM用户访问密钥。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 accessKeyId: process.env.OSS_ACCESS_KEY_ID, accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET, // 填写Bucket名称。 bucket: "examplebucket", }); async function getToken() { // 指定准备工作中创建的角色ARN,格式为acs:ram::$accountID:role/$roleName。 const STS_ROLE = "acs:ram::137****:role/ramosstest"; const STSpolicy = { Version: "1", Statement: [ { Effect: "Allow", Action: "oss:PutObject", Resource: "acs:oss:*:*:examplebucket/*", }, ], }; const result = await stsClient.assumeRole( STS_ROLE, STSpolicy, 3600 // STS过期时间,单位为秒。 ); const { credentials } = result; return credentials; } // 计算签名。 function computeSignature(accessKeySecret, canonicalString) { return crypto.enc.Base64.stringify( crypto.HmacSHA1(canonicalString, accessKeySecret) ); } const date = new Date(); date.setHours(date.getHours() + 1); const policyText = { expiration: date.toISOString(), // 设置policy过期时间。 conditions: [ // 限制上传大小。 ["content-length-range", 0, 1024 * 1024 * 1024], ], }; module.exports.getToken = getToken; module.exports.policyText = policyText; module.exports.computeSignature = computeSignature;
获取客户端签名信息。
打开
express-app.js
文件,执行node express-app.js
命令。const express = require("express"); const app = express(); const { Base64 } = require("js-base64"); const MpUploadOssHelper = require("./uploadOssHelper.js"); const { getToken, policyText, computeSignature } = require("./getToken"); // 获取客户端签名。 app.get("/getFormDataParams", async (req, res) => { // 获取STS。 const { AccessKeySecret, AccessKeyId, SecurityToken } = await getToken(); const policy = Base64.encode(JSON.stringify(policyText)); // policy必须为base64的string。 const signature = computeSignature(AccessKeySecret, policy); const formData = { OSSAccessKeyId: AccessKeyId, signature, policy, SecurityToken, }; res.json(formData); }); app.listen(3001);
通过浏览器输入
http://localhost:3001/getFormDataParams
,获取签名信息。{ "OSSAccessKeyId":"STS.NTm****", "signature":"nS3Z****", "policy":"eyJleH****", "SecurityToken":"CAIS****" }
体验抖音开发者工具直传文件到OSS。
解压项目文件douyin-detail.zip。
打开抖音开发者工具,导入解压后的项目。
修改
page/tt-templates-article
路径下index.js
文件中的host
配置项,其他选项保留默认配置。const app = getApp(); const timeago = require("./timeago.js"); import { templateDataValidator } from "./validator"; // const STS = require("ali-oss").STS; // 填写Bucket外网Endpoint。 const host = 'https://examplebucket.oss-cn-hangzhou.aliyuncs.com'; Page({ onLoad(options) { }, chooseImage: function() { var that = this; // 选择图片。 tt.chooseImage({ count: 1, // 设置图片的数量,默认值是9。 sizeType: ['original', 'compressed'], // 指定上传原图或者压缩图,默认二者均可。 sourceType: ['album', 'camera'], // 指定上传来源是相册还是相机,默认二者均可。 success: function(res) { console.log('原始', res); // 成功选择图片后,获取图片的本地文件路径。 // var localIds = res.tempFiles; var localIds = res.tempFilePaths; // 使用uploadFile上传图片。 that.uploadImage(localIds[0]); } }); }, uploadImage: function(path) { const signature = 'signatureString'; const ossAccessKeyId = 'accessKey'; const key = ''; const securityToken = 'x-oss-security-token'; // 获取token等相关信息。 tt.request({ url:'http://localhost:3001/getFormDataParams', success: function(res) { const {OSSAccessKeyId, policy, signature, SecurityToken} = res.data; console.log('SecurityToken', SecurityToken); // 上传图片。 tt.uploadFile({ url: host, filePath: path, name: 'file', formData: { key: path.split('/').pop(), // 设置文件上传至OSS后的文件路径。 policy, OSSAccessKeyId, signature, // success_action_status: '200', // 使用STS签名时传入securityToken。 'x-oss-security-token': SecurityToken }, success: function(res) { // 上传成功后,服务器返回的相关信息。 var serverId = res.serverId; // 返回服务器ID。 console.log('图片上传成功,服务器ID:', res); // 将serverId发送到服务器端执行保存等操作。 }, fail: function(err) { console.log('图片上传失败:', err); } }); }, fail: function(err) { } }); } });
选择图片,然后上传到OSS。