小程序base64 图片for循环多个展示不了_小程序与OSS的一次邂逅

程序员是值得尊敬的,程序员的双手是魔术师的双手,他们把枯燥无味的代码变成了丰富多彩的软件。

01

使用背景

    在开发过程中,图片文件占用的服务器资源还是比较大的,尤其是在访问量和业务量比较大的地方,这个时候就该要考虑用户图片或者其他文件的上传由后台服务来处理还是由客户端自己消化掉,只扔给后台一串OSS链接就OK 了,那么,在最近几次的项目中,我选择了后者!

02

使用案例

    PC端、H5、小程序使用到需要上传文件的地方比较多,这里我们以小程序上传图片到OSS为例,使用的框架为滴滴的MPX框架。

03

OSS客户端直传介绍

  • 背景信息

    与JavaScript客户端直传实践的原理相同,小程序上传文件到OSS也是利用OSS提供的PostObject接口来实现表单文件上传到OSS。

  • 配置Bucket跨域访问

    其实这块在我之前的关于Vue上传OSS图片的文章中已经提到过一次了,直接上图:

c8641927180feeb9f1e1adc6bc16bf51.png

  • 微信小程序配置域名白名单 1、登陆OSS管理控制台

        2、单击Bucket列表,之后单击目标Bucket名称

    3、在存储空间概览页的访问域名区域查看Bucket域名  4a8159d7cdc8fcfe1d806d27f439313a.png

        4、登陆微信小程序平台,将上传和下载的合法域名填写为Bucket的外网访问域名

93f445055a3e5db056ad1f8c2816cebb.png

03

获取签名和上传部分代码

    阿里云官方给出的解决方案是通过服务端签名或者客户端签名的形式,不过都需要得到服务端的助理,在这块我完全抛开了服务器端,直接由小程序端来处理这些所有的流程。

  • 代码文件截图展示

d2b9a999ffcaa2bfadd1032f42a5e59f.png

    在项目中utils中进行封装小程序上传的整套代码逻辑

  •  oss/Base64.js

const Base64 = {  // private property  _keyStr:    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",  // public method for encoding  encode: function (input) {    var output = "";    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;    var i = 0;    input = Base64._utf8_encode(input);    while (i < input.length) {      chr1 = input.charCodeAt(i++);      chr2 = input.charCodeAt(i++);      chr3 = input.charCodeAt(i++);      enc1 = chr1 >> 2;      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);      enc4 = chr3 & 63;      if (isNaN(chr2)) {        enc3 = enc4 = 64;      } else if (isNaN(chr3)) {        enc4 = 64;      }      output =        output +        this._keyStr.charAt(enc1) +        this._keyStr.charAt(enc2) +        this._keyStr.charAt(enc3) +        this._keyStr.charAt(enc4);    }    return output;  },  // public method for decoding  decode: function (input) {    var output = "";    var chr1, chr2, chr3;    var enc1, enc2, enc3, enc4;    var i = 0;    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");    while (i < input.length) {      enc1 = this._keyStr.indexOf(input.charAt(i++));      enc2 = this._keyStr.indexOf(input.charAt(i++));      enc3 = this._keyStr.indexOf(input.charAt(i++));      enc4 = this._keyStr.indexOf(input.charAt(i++));      chr1 = (enc1 << 2) | (enc2 >> 4);      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);      chr3 = ((enc3 & 3) << 6) | enc4;      output = output + String.fromCharCode(chr1);      if (enc3 != 64) {        output = output + String.fromCharCode(chr2);      }      if (enc4 != 64) {        output = output + String.fromCharCode(chr3);      }    }    output = Base64._utf8_decode(output);    return output;  },  // private method for UTF-8 encoding  _utf8_encode: function (string) {    string = string.replace(/\r\n/g, "\n");    var utftext = "";    for (var n = 0; n < string.length; n++) {      var c = string.charCodeAt(n);      if (c < 128) {        utftext += String.fromCharCode(c);      } else if (c > 127 && c < 2048) {        utftext += String.fromCharCode((c >> 6) | 192);        utftext += String.fromCharCode((c & 63) | 128);      } else {        utftext += String.fromCharCode((c >> 12) | 224);        utftext += String.fromCharCode(((c >> 6) & 63) | 128);        utftext += String.fromCharCode((c & 63) | 128);      }    }    return utftext;  },  // private method for UTF-8 decoding  _utf8_decode: function (utftext) {    var string = "";    var i = 0;    var c = (c1 = c2 = 0);    while (i < utftext.length) {      c = utftext.charCodeAt(i);      if (c < 128) {        string += String.fromCharCode(c);        i++;      } else if (c > 191 && c < 224) {        c2 = utftext.charCodeAt(i + 1);        string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));        i += 2;      } else {        c2 = utftext.charCodeAt(i + 1);        c3 = utftext.charCodeAt(i + 2);        string += String.fromCharCode(          ((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)        );        i += 3;      }    }    return string;  },};export default Base64;
  •  oss/crypto.js

const Crypto = {};(function () {  var base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";  // Crypto utilities  var util = Crypto.util = {    // Bit-wise rotate left    rotl: function (n, b) {      return (n << b) | (n >>> (32 - b));    },    // Bit-wise rotate right    rotr: function (n, b) {      return (n << (32 - b)) | (n >>> b);    },    // Swap big-endian to little-endian and vice versa    endian: function (n) {      // If number given, swap endian      if (n.constructor == Number) {        return util.rotl(n, 8) & 0x00FF00FF |          util.rotl(n, 24) & 0xFF00FF00;      }      // Else, assume array and swap all items      for (var i = 0; i < n.length; i++)        n[i] = util.endian(n[i]);      return n;    },    // Generate an array of any length of random bytes    randomBytes: function (n) {      for (var bytes = []; n > 0; n--)        bytes.push(Math.floor(Math.random() * 256));      return bytes;    },    // Convert a string to a byte array    stringToBytes: function (str) {      var bytes = [];      for (var i = 0; i < str.length; i++)        bytes.push(str.charCodeAt(i));      return bytes;    },    // Convert a byte array to a string    bytesToString: function (bytes) {      var str = [];      for (var i = 0; i < bytes.length; i++)        str.push(String.fromCharCode(bytes[i]));      return str.join("");    },    // Convert a string to big-endian 32-bit words    stringToWords: function (str) {      var words = [];      for (var c = 0, b = 0; c < str.length; c++ , b += 8)        words[b >>> 5] |= str.charCodeAt(c) << (24 - b % 32);      return words;    },    // Convert a byte array to big-endian 32-bits words    bytesToWords: function (bytes) {      var words = [];      for (var i = 0, b = 0; i < bytes.length; i++ , b += 8)        words[b >>> 5] |= bytes[i] << (24 - b % 32);      return words;    },    // Convert big-endian 32-bit words to a byte array    wordsToBytes: function (words) {      var bytes = [];      for (var b = 0; b < words.length * 32; b += 8)        bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);      return bytes;    },    // Convert a byte array to a hex string    bytesToHex: function (bytes) {      var hex = [];      for (var i = 0; i < bytes.length; i++) {        hex.push((bytes[i] >>> 4).toString(16));        hex.push((bytes[i] & 0xF).toString(16));      }      return hex.join("");    },    // Convert a hex string to a byte array    hexToBytes: function (hex) {      var bytes = [];      for (var c = 0; c < hex.length; c += 2)        bytes.push(parseInt(hex.substr(c, 2), 16));      return bytes;    },    // Convert a byte array to a base-64 string    bytesToBase64: function (bytes) {      // Use browser-native function if it exists      if (typeof btoa == "function") return btoa(util.bytesToString(bytes));      var base64 = [],        overflow;      for (var i = 0; i < bytes.length; i++) {        switch (i % 3) {          case 0:            base64.push(base64map.charAt(bytes[i] >>> 2));            overflow = (bytes[i] & 0x3) << 4;            break;          case 1:            base64.push(base64map.charAt(overflow | (bytes[i] >>> 4)));            overflow = (bytes[i] & 0xF) << 2;            break;          case 2:            base64.push(base64map.charAt(overflow | (bytes[i] >>> 6)));            base64.push(base64map.charAt(bytes[i] & 0x3F));            overflow = -1;        }      }      // Encode overflow bits, if there are any      if (overflow != undefined && overflow != -1)        base64.push(base64map.charAt(overflow));      // Add padding      while (base64.length % 4 != 0) base64.push("=");      return base64.join("");    },    // Convert a base-64 string to a byte array    base64ToBytes: function (base64) {      // Use browser-native function if it exists      if (typeof atob == "function") return util.stringToBytes(atob(base64));      // Remove non-base-64 characters      base64 = base64.replace(/[^A-Z0-9+\/]/ig, "");      var bytes = [];      for (var i = 0; i < base64.length; i++) {        switch (i % 4) {          case 1:            bytes.push((base64map.indexOf(base64.charAt(i - 1)) << 2) |              (base64map.indexOf(base64.charAt(i)) >>> 4));            break;          case 2:            bytes.push(((base64map.indexOf(base64.charAt(i - 1)) & 0xF) << 4) |              (base64map.indexOf(base64.charAt(i)) >>> 2));            break;          case 3:            bytes.push(((base64map.indexOf(base64.charAt(i - 1)) & 0x3) << 6) |              (base64map.indexOf(base64.charAt(i))));            break;        }      }      return bytes;    }  };  // Crypto mode namespace  Crypto.mode = {};})();export default Crypto
  • oss/hmac.js

import Crypto from './crypto.js'(function () {  // Shortcut  var util = Crypto.util;  Crypto.HMAC = function (hasher, message, key, options) {    // Allow arbitrary length keys    key = key.length > hasher._blocksize * 4 ?      hasher(key, { asBytes: true }) :      util.stringToBytes(key);    // XOR keys with pad constants    var okey = key,      ikey = key.slice(0);    for (var i = 0; i < hasher._blocksize * 4; i++) {      okey[i] ^= 0x5C;      ikey[i] ^= 0x36;    }    var hmacbytes = hasher(util.bytesToString(okey) +      hasher(util.bytesToString(ikey) + message, { asString: true }),      { asBytes: true });    return options && options.asBytes ? hmacbytes :      options && options.asString ? util.bytesToString(hmacbytes) :        util.bytesToHex(hmacbytes);  };})();export default Crypto
  • oss/sha1.js

import Crypto from './crypto.js'(function () {  // Shortcut  var util = Crypto.util;  // Public API  var SHA1 = Crypto.SHA1 = function (message, options) {    var digestbytes = util.wordsToBytes(SHA1._sha1(message));    return options && options.asBytes ? digestbytes :      options && options.asString ? util.bytesToString(digestbytes) :        util.bytesToHex(digestbytes);  };  // The core  SHA1._sha1 = function (message) {    var m = util.stringToWords(message),      l = message.length * 8,      w = [],      H0 = 1732584193,      H1 = -271733879,      H2 = -1732584194,      H3 = 271733878,      H4 = -1009589776;    // Padding    m[l >> 5] |= 0x80 << (24 - l % 32);    m[((l + 64 >>> 9) << 4) + 15] = l;    for (var i = 0; i < m.length; i += 16) {      var a = H0,        b = H1,        c = H2,        d = H3,        e = H4;      for (var j = 0; j < 80; j++) {        if (j < 16) w[j] = m[i + j];        else {          var n = w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16];          w[j] = (n << 1) | (n >>> 31);        }        var t = ((H0 << 5) | (H0 >>> 27)) + H4 + (w[j] >>> 0) + (          j < 20 ? (H1 & H2 | ~H1 & H3) + 1518500249 :            j < 40 ? (H1 ^ H2 ^ H3) + 1859775393 :              j < 60 ? (H1 & H2 | H1 & H3 | H2 & H3) - 1894007588 :                (H1 ^ H2 ^ H3) - 899497514);        H4 = H3;        H3 = H2;        H2 = (H1 << 30) | (H1 >>> 2);        H1 = H0;        H0 = t;      }      H0 += a;      H1 += b;      H2 += c;      H3 += d;      H4 += e;    }    return [H0, H1, H2, H3, H4];  };  // Package private blocksize  SHA1._blocksize = 16;})();export default Crypto
  • oss/config.js 这块进行管理OSS的秘钥之类的 安全建议不要在客户端保存,这块暂时不考虑这些

var fileHost = "Bucket域名"var config = {  //aliyun OSS config  uploadImageUrl: `${fileHost}`, //默认存在根目录,可根据需求改  AccessKeySecret: 'AccessKeySecret',  OSSAccessKeyId: 'OSSAccessKeyId',  timeout: 87600 //这个是上传文件时Policy的失效时间};export default config
  • oss/UploadAliyun.js

import env from './config.js'import Base64 from './Base64.js'require('./hmac.js');require('./sha1.js');import Crypto from './crypto.js'const OSSImg = function (filePath, dir, successc, failc) {    if (!filePath || filePath.length < 9) {        wx.showModal({            title: '图片错误',            content: '请重试',            showCancel: false,        })        return;    }    const filrname = filePath.replace('wxfile://', '');    //我直接拿微信本地的名字当做传到服务器上的名字了,dir传的是images/,表示要传到这个目录下 这块可以进行自定义    const aliyunFileKey = dir + filrname    // const aliyunFileKey = fileW + '' + (new Date().getTime()) + '_' + objectId + '.mp4';    //const aliyunFileKey = fileW    const aliyunServerURL = env.uploadImageUrl;//OSS地址,需要https    const accessid = env.OSSAccessKeyId;    //const policyBase64 = env.Policy;    //const signature = env.Signature;    const policyBase64 = getPolicyBase64();    const signature = getSignature(policyBase64);//获取签名    wx.showLoading({        title: '上传中....',    })    wx.uploadFile({        url: aliyunServerURL,        filePath: filePath,        name: 'file',//必须填file        formData: {            'key': aliyunFileKey,            'policy': policyBase64,            'OSSAccessKeyId': accessid,            'signature': signature,            'success_action_status': '200',        },        success: function (res) {            if (res.statusCode != 200) {                failc(new Error('上传错误:' + JSON.stringify(res)))                return;            }            wx.hideLoading()            successc(`${aliyunServerURL}/${dir}${filrname}`);        },        fail: function (err) {            err.wxaddinfo = aliyunServerURL;            failc(err);        },    })}const getPolicyBase64 = function () {    let date = new Date();    date.setHours(date.getHours() + env.timeout);    let srcT = date.toISOString();    const policyText = {        "expiration": srcT, //设置该Policy的失效时间,超过这个失效时间之后,就没有办法通过这个policy上传文件了        "conditions": [            ["content-length-range", 0, 5 * 1024 * 1024] // 设置上传文件的大小限制,5mb        ]    };    const policyBase64 = Base64.encode(JSON.stringify(policyText));    return policyBase64;}const getSignature = function (policyBase64) {    const accesskey = env.AccessKeySecret;    const bytes = Crypto.HMAC(Crypto.SHA1, policyBase64, accesskey, {        asBytes: true    });    const signature = Crypto.util.bytesToBase64(bytes);    return signature;}export {OSSImg}
  • utils/uploadImg.js 页面调用上传主入口

const oss = require("./oss/UploadAliyun");const imgFile = {  upimgTOSS(dir = "images/") {    return new Promise((resolve, reject) => {      wx.chooseImage({        count: 1,        sizeType: ["original", "compressed"],        sourceType: ["album", "camera"],        success: function (res) {          oss.OSSImg(res.tempFilePaths[0], dir, (re) => {            resolve(re);          });        },      });    });  },};export { imgFile };
  • 业务引入与调用

d1e8df3151906f53c28f3a0f72230572.png

31bdab433261fb3f5a36dcda867bd285.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值