阿里云OSS回调实战(Vue + Django + DRF)
参考资料:快速搭建移动应用直传服务, Web端上传数据至OSS
摘要
近期开发过程中有OSS大文件直传(C端)并进行相应数据库操作(S端)的需求,在查找资料过程中发现相关资料较少,特此记录。
本文主要介绍了基于Vue + Django + DjangoRESTfulFramework的应用程序接入阿里云OSS的过程,主要用到的SDK有:
Browser.js,
aliyunsdkcore, aliyunsdksts
背景信息
Web端常见的上传方法是用户在浏览器或App端上传文件到应用服务器,应用服务器再把文件上传到OSS;和数据直传到OSS相比,以上方法有三个缺点:上传慢、扩展性差、费用高。基于此,本文将采用直传OSS的方式进行应用开发。
前置工作
技术方案
下载SDK
WEB端:
$ npm install ali-oss
服务端:
$ pip install oss2
$ pip install aliyun-python-sdk-sts
服务端
views.py
from aliyunsdkcore import client as AliyunClient
from aliyunsdksts.request.v20150401 import AssumeRoleRequest
import oss2
import json
ENDPOINT = 'oss-cn-beijing.aliyuncs.com' # 假设为北京节点
ACCESS_KEY_ID = 'YOUR ACCESS KEY ID'
ACCESS_KEY_SECRET = 'YOUR ACCESS KEY SECRET'
BUCKET_NAME = 'YOUR BUCKET NAME'
ROLE_ARN = 'YOUR ROLE ARN'
POLICY_TEXT = '{"Version": "1", "Statement": [{"Action": ["oss:*"], "Effect": "Allow", "Resource": ["acs:oss:*:*:YOUR BUCKET NAME/*"]}]}'
def get_sts_token():
client = AliyunClient.AcsClient(ACCESS_KEY_ID, ACCESS_KEY_SECRET, 'cn-beijing')
req = AssumeRoleRequest.AssumeRoleRequest()
req.set_accept_format('json')
req.set_RoleArn(ROLE_ARN)
req.set_RoleSessionName('test')
req.set_Policy(POLICY_TEXT)
body = client.do_action_with_exception(req)
token = json.loads(oss2.to_unicode(body))
return token
# 认证管理View
class STSView(views.APIView):
authentication_classes = (AuthenticationView,)
permission_classes = ()
# 开发过程中可以添加认证log,在此不表
def get(self, request):
token = get_sts_token()
token['Credentials']['BucketName'] = BUCKET_NAME # 添加BucketName字段
token['Credentials']['Endpoint'] = 'oss-cn-beijing' # 添加Endpoint字段
return SuccessResponse(token['Credentials'])
# echo接收到的回调参数
def callback_echo(request):
return request.data
urls.py
...
urlpatterns = [
path('sts/', STSView.as_view(), name='instances')
path('callback/', callback_echo(), name='callback')
]
WEB前端代码
<template>
<div>
<button @click="getToken">getToken</button> // 从服务器获取STS Token
<input id="file" type="file" @change="onLoad"/> // 选取文件
<button @click="onUpload">upload</button> // 上传文件
</div>
</template>
<script>
export default {
name: 'UploadCallback',
props: {
msg: String
},
data() {
return {
fileList: [], // 用来记录文件信息
credentials: null // 用来记录从服务器获取到的token、bucket、endpoint等信息
}
},
methods: {
getToken() {
const axios = require('axios');
axios.post('https://server_address/api/sts/', {}, {
headers: {
'token': `token` // 用于认证用户身份
}
}).then((res) => {
this.credentials = res.data.data
})
},
onLoad(file) {
this.fileList = file.target.files
console.log(file.target.files[0]);
},
onUpload() {
let callback = {
url: 'http://server_address/api/callback/',
body:'bucket=${bucket}&object=${object}&etag=${etag}'+
'&size=${size}&mimeType=${mimeType}&var1=${x:var1}',
// ${bucket}、${object}等字段是OSS规定的字段,会在处理数据过程中自动填充相应参数,详见官方文档;
// ${x:var1}字段是用户自定义的,“x:”不可省略
contentType: 'application/x-www-form-urlencoded', // 指定contentType
customValue: { // 若key值在上面的body中出现(如:${x:var1}),则会将key对应的值填充在对应位置
var1: '123123',
}
}
let options = { // 上传oss的信息
region: this.credentials.Endpoint,
accessKeyId: this.credentials.AccessKeyId,
accessKeySecret: this.credentials.AccessKeySecret,
stsToken: this.credentials.SecurityToken,
bucket: this.credentials.BucketName,
}
this.putObject(options, this.fileList[0], callback);
},
async putObject(options, data, callback) { // 上传文件
const OSS = require('ali-oss');
const client = new OSS(options);
try {
const result = await client.put('exampledir/' + data.name, data, {callback: callback});
console.log(result);
} catch (e) {
console.log(e);
}
}
}
</script>