uniapp不支持直接使用browserjs上传OBS?

496 阅读7分钟

前言

最近老板提了一个需求是要在我们给客户PDA扫码机上的app添加个拍照上传附件的功能,当时心想:手拿把掐,10分钟搞定。代码写完,本地运行上传正常,真机运行OBS初始化时提示 console is undefinde 嗯? 什么鬼?我没写console呀,哪来的报错?

我用的是华为云官网下载的SDK: OBS BrowserJS SDK

image.png

在页面上进行引入:

import ObsClient from '../../utils/esdk-obs-browserjs-without-polyfill.3.22.3.min.js';

进行的文件上传, 百思不得骑姐,遇事不决,开始百度。看到有帖子说不支持uniapp? 那咋搞?在uniapp社区看到一篇帖子提出了两种方法: ask.dcloud.net.cn/article/387…

  1. 前端产生签名前端直传华为云OBS:好处是不经过自家服务器周转,减少一个环节,上传速度更快。坏处:前端产生签名的过程中,会将 AK,SK 等核心账号信息暴露,是极其危险的。
  2. 后端签名前端获取后直传华为云OBS:好处同上,而且由于是后端生成签名,前端获取有时效性的签名后直传云端,因此没有泄露核心账号信息的风险。

文章中介绍了第二种方法,卑微的我不敢麻烦我的后端老板,所以使用了第一种方法。

开始编写

1.创建view.vue文件添加一个拍照按钮

<template>
    <view class="btn2" @click="uploadFile">拍照</view>
</template>

2.在methods中创建uploadFile()方法

methods: {
    //添加附件文件
    uploadFile(){
        uni.chooseImage({
            count: 1,
            sizeType: ['original', 'compressed'],
            sourceType: ['camera', 'album'], //这要注意,camera掉拍照,album是打开手机相册
            success: (res) => {
                this.tempFileArr.push(res); //存储
            }
        });
    }
}

3.添加一个上传按钮

<template>
    <view class="btn2" @click="uploadFile">拍照</view>
    <view class="btn2" @click="saveBill">上传</view>
</template>

4.创建saveBill()方法

遍历 tempFileArr 数组,提取出每个附件进行批次上传

saveBill(){
    for(let i = 0;i < this.tempFileArr.length;i++){
        const tempFileItem = this.tempFileArr[i];
        const fileSplit = tempFileItem.tempFiles[0].path.split('/'); //文件名称+后缀
        const type = fileSplit[fileSplit.length - 1].split(".")[1]; //文件后缀
        //设定policy内容
        const OBSPolicy = {   
            "expiration": '2025-12-31T12:00:00.000Z', // uniapp ios Android 端 必须为此格式
            "conditions": [
                { "bucket": "Bucket name" },        //桶名称
                { 'key': key } // 格式 'xx/a.jpg' 路径/名称.格式 (路径选填)
            ]
        }
        
        const policyEncoded = getPolicyEncode(OBSPolicy); //计算policy编码值
        const signature = getSignature(policyEncoded, config.SecretKey); //计算 signature
        
        //上传 使用upload组件上传即可
        const formData = {
          "key": key, //地址和文件名
          "AccessKeyId": `自己的AccessKeyId`,
          "Policy": policyEncoded,
          "Signature": signature
        }
        /**注意我们使用:policy 编译健全内容的时候:conditions 数组里面的值,要与formdata 里面的值保持一致,不然会报错,!!!!注意,不写status的时候, 300 已下都是成功**/
        uni.uploadFile({
            url: Configuration.EndPoint,
            filePath: tempFileItem.tempFiles[0].path,//临时文件地址
            name: 'file',
            formData: formData,
            success: (res)=>{ //成功的回调
                console.log("res", res)
            },
            fail: (error)=>{
                console.log("error", error)
            }
        });
    }
}

5.导入计算policy编码值和signature方法文件,感谢大佬~文件来源:pan.baidu.com/s/1s6VRkqFr… 提取码: ia78

创建OBS文件夹,存放计算方法

image.png

// 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;
   }
}
module.exports = Base64;
//Configuration.js
//指定OBS服务相关信息:AK,SK,EndPoint
var Configuration = {
	AccessKeyId: '', //AK
	bucket: '',
	SecretKey: '', //SK
	EndPoint: '', //上传文件的路径
};

module.exports = Configuration;
//crypto.js
/*!
 * Crypto-JS v1.1.0
 * http://code.google.com/p/crypto-js/
 * Copyright (c) 2009, Jeff Mott. All rights reserved.
 * http://code.google.com/p/crypto-js/wiki/License
 */

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 = {};
})();

module.exports = Crypto;
//getPolicy.js
const Base64 = require('./Base64.js');

function getPolicyEncode(policy) {
	const encodedPolicy = Base64.encode(JSON.stringify(policy));
	return encodedPolicy;
}

module.exports = getPolicyEncode;
//GetSignature.js
require('./hmac.js');
require('./sha1.js');
const Crypto = require('./crypto.js');
const Base64 = require('./Base64.js');

//利用SK计算Signature信息
function getSignature(policyEncoded, SecretKey) {
	const bytes = Crypto.HMAC(Crypto.SHA1, policyEncoded, SecretKey, {
		asBytes: true
	});

	const signature = Crypto.util.bytesToBase64(bytes);
	return signature;
}

module.exports = getSignature;
//hmac.js
/*!
 * Crypto-JS v1.1.0
 * http://code.google.com/p/crypto-js/
 * Copyright (c) 2009, Jeff Mott. All rights reserved.
 * http://code.google.com/p/crypto-js/wiki/License
 */

const Crypto = require('./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);

	};

})();

module.exports = Crypto;
//sha1.js
/*!
 * Crypto-JS v1.1.0
 * http://code.google.com/p/crypto-js/
 * Copyright (c) 2009, Jeff Mott. All rights reserved.
 * http://code.google.com/p/crypto-js/wiki/License
 */

const Crypto = require('./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;

})();

module.exports = Crypto;

6.在view.vue页面导入计算方法

const getPolicyEncode = require('./OBS/getPolicy.js');
const getSignature = require('./OBS/GetSignature.js');
const Configuration = require('./OBS/Configuration.js');

注意:uniapp ios Android 端如果上传报 403 Crypto.js文件中的 113行文件注释即可

总结

好了,真机运行后成功上传。希望uniapp能过快点支持一下 OBS BrowserJS SDK,否则太麻烦了。 华为云参考链接:support.huaweicloud.com/api-obs/obs…support.huaweicloud.com/api-obs/obs…support.huaweicloud.com/intl/zh-cn/…