浅显易懂,轻松搞定OSS的签名直传头像功能

作者 : 开心源码 本文共5383个字,预计阅读时间需要14分钟 发布时间: 2022-05-13 共206人阅读

自己的网站(https://www.gf-app.cn)目前只做了第三方登录。主要是考虑用手机号登录,就得接短信验证码服务。怕被人恶意刷短信,就得做防刷机制,否则有被刷短信费的风险。
初次登录会自动获取客户在支付宝的头像和昵称来自动注册。客户可以通过修改资料的重新上传头像。

茴香豆的“茴”字有五种写法,上传头像的方法,同样有5种。

建议都使用第三方图床(以阿里云OSS为例)。主要是看中了能够自由缩放图片尺寸。这5种方法具体的优缺点评比见后面的表格。

  1. 直接将图片上传到自己的服务器。

就是图片通过表单提交到后台,后台将图片保存到自己服务器的某个地方后,继续后续逻辑。
难度:☆
推荐度:☆

  • 简单,这是最基本的功能实现,一个后台就可完成;
  • 所有图片都保存在自己的服务器上,占用了硬盘空间。而硬盘空间是需要花钱买的;
  • 图片越多,花费越高!不推荐。
  1. 先上传再转存图床(使用OSS)

先用方法1实现将图片上传到自己的服务器,再调用阿里云OSS的sdk,将图片转存过去。
难度:☆☆
推荐度:☆☆

  • 难度方面,相对方法1,添加了转存的逻辑。由于有现成的sdk供调用,只要要学习oss怎样配置就可。一个后台就可完成;
  • 因为图片还是得先上传到自己服务器,仍然避免不了占用硬盘的问题。而且为了节省硬盘,还需要写代码清除自己服务器的图片。此外转存带来了图片的二次上传,代码的执行时间会变的更长;
  • 在项目的前期研发阶段,可以当做临时方案使用。
  1. javascript直传

前台直传需要用到安全加密算法的数字签名。这种方法里,签名由前台生成,生成好的签名和图片即可以一律由前台代码发到OSS端了,解放了后台。
难度:☆☆☆(前台)
推荐度:☆☆

  • 需要学习如何生成数字签名,一个前台可以搞定;
  • 由于是直接上传,所以不会占用服务器硬盘;
  • 因为签名需要前台生成,所以敏感性数据比方access_id_key就得写到js代码里了。前台代码几乎是透明的,假如有懂的人,直接把你的密钥拿走干别的了,你还得傻乎乎的给人家续费;
  • 有安全风险,不推荐!
  1. 服务端签名后javascript直传

流程和方法3类似,只是数字签名交给了后台。javascript带着签名将图片上传给OSS。
难度:☆☆☆☆
推荐度:☆☆☆☆☆

  • 后台需要生成加密签名,并提供给前台使用,这里有少量难度,不过可以参考阿里云的demo ,需要前后台进行配合;
  • 这种方法很好用,但是有肯定的业务局限性。比方客户上传了照片,但是不点击保存就把网页关了,那oss空间就白白白费了。
  • 根据自身业务选择,强烈推荐!
  1. 服务端签名直传后设置回调

流程相比照方法4,添加了回调逻辑。后台先生成签名,js带着签名上传图片之后,阿里云会主动调用你提供的接口完成后续操作。
难度:☆☆☆☆☆
推荐度:☆☆☆☆

  • 和方法4相比,几乎没有缺点,也不怕客户中途关闭网页,没有业务局限性。
  • 生成签名时需要添加回调地址和回传参数。
  • 尽管有demo参考,但回调地址必需在公网环境下才能调试,不太方便;
  • 由于不好调试,比较推荐。

优缺点对照表

图片上传对照.png

编码部分

在我这次的修改头像逻辑中,我选择了方法4。假如客户一次只选择一张图片,那么其实可以用选择好图片立即上传的方法,不给客户不点“上传”按钮的机会。由于客户是最懒的,不要妄图教育客户,能让他点一下,就不应该让他点第二下

阿里云提供的服务器签名直传的demo是这样的,需要让人点两下,这不符合我的设计。

oss的上传demo.png

所以我们需要对这个demo里的代码进行修改,以实现我们一次点击完成上传的需求。
这个js的demo,是基于plupload-2.1.2版本。我们需要重新定义FilesAdded事件的解决逻辑。下载了阿里云的demo后,打开upload.js,可以看见这样的代码:

FilesAdded: function(up, files) {            plupload.each(files, function(file) {                document.getElementById('ossfile').innerHTML += '<div id="' + file.id + '">' + file.name + ' (' + plupload.formatSize(file.size) + ')<b></b>'                +'<div class="progress"><div class="progress-bar" style="width: 0%"></div></div>'                +'</div>';            });        },

这个FilesAdded事件,就是当plupload组件拿到要上传的图片之后触发的。阿里云的demo是显示你选择的图片名和文件大小。而我的逻辑则需要直接触发上传。所以我的代码是这样写的:

// 增加文件uploader.bind("FilesAdded", function (up, files) {    set_upload_param(up);    return false;});

这样一来,我的上传体验就变成了这样:

我的上传.png

操作起来是这样的:

uxdf0-75bsm.gif

怎样样,体验一下子就好多了吧!

附上完整的代码:
前台javascript

var oss_token = {{ oss_token }}// 上传签名,这里直接输出在页面了。建议头像上传之后自动刷新一下页面。这个token只能用一次。当然你也可以使用同步ajax去服务端获取。// console.log(oss_token);// console.log(current_uid);// 设置上传参数function set_upload_param(up) {    // 获取上传签名    obj = oss_token;    host = obj['host'];    policyBase64 = obj['policy'];    accessid = obj['accessid'];    signature = obj['signature'];    expire = parseInt(obj['expire']);    callbackbody = obj['callback'];    key = obj['dir'] + "/" + current_uid;  //头像的地址就用user_id来当做key了,可以通过拼接拿到地址,减少读库。    timestamp = Date.parse(new Date()) / 1000;    new_multipart_params = {        'key': key,        'policy': policyBase64,        'OSSAccessKeyId': accessid,        'success_action_status': '200', //让服务端返回200,不然,默认会返回204        // 'callback' : callbackbody,        'signature': signature,    };    console.log(new_multipart_params);    up.setOption({        'url': host,        'multipart_params': new_multipart_params    });    up.start();}// 取得头像路径function get_avatar_path() {    obj = oss_token;    host = obj['host'];    key = obj['dir'] + "/" + current_uid;    timestamp = Date.parse(new Date()) / 1000;    return host + "/" + key + "?v=" + timestamp;  //通过修改的时间戳作为附加参数,可以防止浏览器缓存或者cdn导致图片不升级}// 实例化上传组件var uploader = new plupload.Uploader({    runtimes : 'html5,flash,silverlight,html4',    browse_button : 'selectfiles',   //选择文件按钮的元素ID    flash_swf_url : 'lib/plupload-2.1.2/js/Moxie.swf',    silverlight_xap_url : 'lib/plupload-2.1.2/js/Moxie.xap',    url : 'http://oss.aliyuncs.com',    filters: {        mime_types: [ //只允许上传图片            {title: "Image files", extensions: "jpg,jpeg,gif,png"},        ],        max_file_size: '5mb', //最大只能上传5mb的文件        prevent_duplicates: true //不允许选取重复文件    },});uploader.init();/** 绑定方法 **/// 增加文件uploader.bind("FilesAdded", function (up, files) {    set_upload_param(up);   //组装签名,执行上传    return false;});//上传成功uploader.bind("FileUploaded", function (up, file, info) {    if (info.status == 200) {        // 将新头像地址保存到数据库    } else {        errorMsg("上传失败");    }});//弹出错误提醒function errorMsg(msg) {    var tips = $('#topTips_avatar');    tips.text(msg);    tips.fadeIn(100);    setTimeout(function () {        tips.fadeOut(100);    }, 2000);}

相对完整的python后台代码

# manage.py# 获取直传token    def get_token(self, bucket_name, prefix=""):        now = int(time.time())        expire_syncpoint = now + self.expire_time        # expire_syncpoint = 1612345678        expire = OssTokenManager.get_iso_8601(expire_syncpoint)        policy_dict = {}        policy_dict['expiration'] = expire        condition_array = []        array_item = []        array_item.append('starts-with')        array_item.append('$key')        array_item.append(prefix)        condition_array.append(array_item)        policy_dict['conditions'] = condition_array        policy = json.dumps(policy_dict).strip()        policy_encode = base64.b64encode(policy.encode())        h = hmac.new(OSS_ACCESS_KEY_SECRET.encode(), policy_encode, sha)        sign_result = base64.encodebytes(h.digest()).strip()        token_dict = {}        token_dict['accessid'] = OSS_ACCESS_KEY_ID        token_dict['host'] = "http://%s" % self.get_domain(bucket_name)        token_dict['policy'] = policy_encode.decode()        token_dict['signature'] = sign_result.decode()        token_dict['expire'] = expire_syncpoint        token_dict['dir'] = prefix        # token_dict['callback'] = base64_callback_body.decode()        result = json.dumps(token_dict)        return result    def get_domain(self, bucket_name):        # print(bucket_name)        if bucket_name in OSS_BUCKETNAME:            return OSS_BUCKETNAME[bucket_name]["domain"]        else:            return ""
# config.py# oss配置OSS_ACCESS_KEY_ID = 'abcd1234'  //改成你自己的OSS_ACCESS_KEY_SECRET = '1234abcd'    //改成你自己的OSS_END_POINT = 'http://oss-cn-beijing.aliyuncs.com'    //改成你自己的# bucket设置 {类别/用途:{bucket:BUCKET, domain:域名, style:[STYLE]}OSS_BUCKETNAME = {    # 头像    "avatar": {"bucket": 'xx-avatar', "domain": "xx-avatar.oss-cn-beijing.aliyuncs.com",               "style": ["avatar_middle_w80h80"]},}

这份文档就写在这里了,快去试试吧!假如有帮助,请帮我点个赞。假如有不清楚的地方或者可以继续优化的地方,欢迎在下方留言探讨哦。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 浅显易懂,轻松搞定OSS的签名直传头像功能

发表回复