前端上传的图片很占用服务器资源,因此寻找解决办法看到了七牛云的图片上传功能,由于七牛云只提供了单张图片上传的api,我使用循环的方式实现了前端上传多图的效果。实现过程中踩到了两个坑值得记录一下,第一是循环中的异步回调函数导致的key和token错位,其次就是回调函数的作用域问题。

前端使用的是dcloud的uniapp框架,大致结构与微信小程序没有差别,基本上小程序的api在uniapp中也有对应的api。

前端使用

首先下载七牛云提供的前端sdk,解压到本地将 qiniuUploader.js 引入到需要上传图片的页面使用。

这里我放到了components/qiniuUploader目录下。

<template>
	<view>
		<button type="primary" @click="qupload">选择图片</button>
		<button type="primary" @click="test">七牛多图</button>
	</view>
</template>

<script>
	const qiniuUploader = require("../../components/qiniuUploader");
	export default {
		data() {
			return {
				token: [],
				key: [],
				filePath: []
			}
		},
	methods: {
			qupload() {
				// 选择图片
				uni.chooseImage({
					count: 4,
					success: (res) => {
						this.filePath = this.filePath.concat(res.tempFilePaths);
						for (var i = 0; i < 4; i++) {
							// this.key[i] = md5(Math.random().toString(36).substr(2));一开始是在这里生成后端生成token所需的key,由于没有考虑到回调函数的异步导致了key和token不匹配造成的上传失败,最后通过将key放到后端生成,前端请求后端接口时一起获取解决了这个问题
							uni.request({
								url: 'http://api.nauzone.cn/?service=',//后端生成key和token的接口
								success: (re) => {
									console.log(re.data.data);
									// this.token.push(re.data.data);
									//将token和key放入数组中备用,这里还有一个问题就是回调函数的this指向问题,经过经验事实发现,如果回调函数的格式写成匿名函数 success:function(){ }的样式将会导致this指向变为函数内部,这是将报this没有token和key的属性,虽然这已经在全局声明了。写成success: (re) => { } 则没有任何问题,此时回调函数内部就是全局。还有一个坑也是回调函数的异步导致的在同一个执行期上下文内,在回调函数的内部push的值在外部不能立即获取,这里需要注意一下。
									this.token.push(re.data.data.token);
									this.key.push(re.data.data.key);
									
								}
							});
						}
					}
				});
				
			},
			test() {//循环上传图片
				for (var i = 0; i < 4; i++) {
					//console.log(this.filePath[i]);
					
					console.log(this.key[i]);
					console.log(this.token[i]);
					qiniuUploader.upload(this.filePath[i], (res) => {
						console.log(res.imageURL);
					}, (error) => {
						var a = JSON.stringify(error);
						console.log('error: ' + a);
					}, {
						region: 'ECN',
						domain: 'pn7r16wx7.bkt.clouddn.com', // // bucket 域名,下载资源时用到。如果设置,会在 success callback 的 res 参数加上可以直接使用的 ImageURL 字段。否则需要自己拼接
						key: this.key[i], // [非必须]自定义文件 key。如果不设置,默认为使用微信小程序 API 的临时文件名
						// 以下方法三选一即可,优先级为:uptoken > uptokenURL > uptokenFunc
						uptoken: this.token[i],
					});
				}
			}
		}
	</script>

后端token生成

七牛云上传要求由key生成一个上传凭证token,token有3中方法生成并给七牛云验证。第一就是由其他程序生成token后在调用时将token一起上传,第二是在前端构造一个token生成函数,第三是将后端生成token的api地址发给七牛。无论通过那种方式,都要求key和token要一一对应起来,否则将报403错误。

我采用的是第一种方法,由后端生成key和token发送给前端,前端接收后在调用时将收到的token和key发给七牛云即可。后端采用phalapi开源php框架,引入了七牛云服务器端的sdk后,重写了一下便能引入实现了。

use App\Common\Qiniu;

/**
     * 七牛图片文件上传
     * @desc 只能上传单个图片文
     * @return array token  返回七牛云上传凭证token
     * @return string key  返回生成token的key
     */
    public function qiniu() {
        $rs = array();
        $rs['key'] = md5(uniqid(microtime(true),true));//生成唯一字符串
        $uploader = new Qiniu('七牛云ak’,'七牛云sk');
        $rs['token'] = $uploader->uploadToken('upload',$rs['key']);
        return $rs;
    }