├── README.md ├── client ├── .wing │ └── launch.json ├── app.js ├── app.json ├── app.wxss ├── jsconfig.json ├── pages │ ├── index │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ └── logs │ │ ├── logs.js │ │ ├── logs.json │ │ ├── logs.wxml │ │ └── logs.wxss └── utils │ ├── qiniuUploader.js │ └── util.js └── server └── qiniuTokenServer.js /README.md: -------------------------------------------------------------------------------- 1 | # 微信小程序-七牛图片上传 2 | 3 | ### 说明: 4 | 5 | 实现了直接从客户端上传图片到七牛的功能,包含生成uptoken的服务端。 6 | 7 | ### 数据接口: 8 | 9 | - https://aime.getweapp.com/qiniu/uptoken 10 | - 自己uptoken服务端api 11 | 12 | ### 目录结构: 13 | 14 | - client — 客户端 15 | - server — 获取uptoken服务端 16 | 17 | ### 开发环境: 18 | 19 | 微信web开发者工具 v0.11.122100 20 | 21 | ### 项目截图: 22 | 23 | https://www.getweapp.com/project?projectId=5880baaa52e1e8733dc567de 24 | 25 | ### 感谢: 26 | 27 | 本项目原始版本由gpake提供:https://github.com/gpake/qiniu-wxapp-sdk 28 | -------------------------------------------------------------------------------- /client/.wing/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "调试微信小程序", 6 | "type": "weapp", 7 | "request": "launch", 8 | "project": "${workspaceRoot}" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /client/app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | //调用API从本地缓存中获取数据 5 | var logs = wx.getStorageSync('logs') || [] 6 | logs.unshift(Date.now()) 7 | wx.setStorageSync('logs', logs) 8 | }, 9 | getUserInfo:function(cb){ 10 | var that = this; 11 | if(this.globalData.userInfo){ 12 | typeof cb == "function" && cb(this.globalData.userInfo) 13 | }else{ 14 | //调用登录接口 15 | wx.login({ 16 | success: function () { 17 | wx.getUserInfo({ 18 | success: function (res) { 19 | that.globalData.userInfo = res.userInfo; 20 | typeof cb == "function" && cb(that.globalData.userInfo) 21 | } 22 | }) 23 | } 24 | }); 25 | } 26 | }, 27 | globalData:{ 28 | userInfo:null 29 | } 30 | }) 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /client/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages":[ 3 | "pages/index/index", 4 | "pages/logs/logs" 5 | ], 6 | "window":{ 7 | "backgroundTextStyle":"light", 8 | "navigationBarBackgroundColor": "#238efa", 9 | "navigationBarTitleText": "七牛图片上传", 10 | "navigationBarTextStyle":"light" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /client/app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | .container { 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | justify-content: space-between; 8 | padding: 200rpx 0; 9 | box-sizing: border-box; 10 | } 11 | -------------------------------------------------------------------------------- /client/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | 4 | }, 5 | "exclude": [ 6 | ] 7 | } -------------------------------------------------------------------------------- /client/pages/index/index.js: -------------------------------------------------------------------------------- 1 | const qiniuUploader = require("../../utils/qiniuUploader"); 2 | //index.js 3 | 4 | // 初始化七牛相关参数 5 | function initQiniu() { 6 | var options = { 7 | region: 'ECN', // 华东区,生产环境应换成自己七牛帐户bucket的区域 8 | uptokenURL: 'https://aime.getweapp.com/qiniu/uptoken', // 生产环境该地址应换成自己七牛帐户的token地址,具体配置请见server端 9 | domain: 'https://oh39iobj6.qnssl.com/' // 生产环境该地址应换成自己七牛帐户对象存储的域名 10 | }; 11 | qiniuUploader.init(options); 12 | } 13 | 14 | //获取应用实例 15 | var app = getApp() 16 | Page({ 17 | data: { 18 | imageObject: {} 19 | }, 20 | //事件处理函数 21 | onLoad: function () { 22 | console.log('onLoad') 23 | var that = this; 24 | }, 25 | didPressChooesImage: function() { 26 | var that = this; 27 | didPressChooesImage(that); 28 | } 29 | }); 30 | 31 | function didPressChooesImage(that) { 32 | initQiniu(); 33 | // 微信 API 选文件 34 | wx.chooseImage({ 35 | count: 1, 36 | success: function (res) { 37 | var filePath = res.tempFilePaths[0]; 38 | // 交给七牛上传 39 | qiniuUploader.upload(filePath, (res) => { 40 | that.setData({ 41 | 'imageObject': res 42 | }); 43 | }, (error) => { 44 | console.error('error: ' + JSON.stringify(error)); 45 | }); 46 | } 47 | } 48 | // , { 49 | // region: 'ECN', 50 | // domain: 'balxqjka.btk.clouddn.com', 51 | // uptokenURL: 'myServer.cpm/api/uptoken' 52 | // } 53 | ) 54 | } 55 | -------------------------------------------------------------------------------- /client/pages/index/index.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /client/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | hash: {{imageObject.hash}}\n\n 10 | key: {{imageObject.key}}\n\n 11 | imageURL: {{imageObject.imageURL}} 12 | 13 | 14 | -------------------------------------------------------------------------------- /client/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | /**index.wxss**/ 2 | 3 | text { 4 | word-break: break-all; 5 | color:gray; 6 | line-height:1.3; 7 | } 8 | 9 | .main { 10 | height: 100%; 11 | display: flex; 12 | flex-direction: column; 13 | align-items: center; 14 | justify-content: space-between; 15 | padding: 100rpx 0; 16 | box-sizing: border-box; 17 | 18 | } 19 | 20 | .image-container { 21 | background-color: #f2f2f2 22 | } 23 | 24 | .data { 25 | padding:0 25px; 26 | text-align: left; 27 | display: block; 28 | font-size: 15px; 29 | word-break:break-all; 30 | } 31 | 32 | button { 33 | margin-bottom: 20px; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /client/pages/logs/logs.js: -------------------------------------------------------------------------------- 1 | var util = require('../../utils/util.js') 2 | Page({ 3 | data: { 4 | logs: [] 5 | }, 6 | onLoad: function () { 7 | this.setData({ 8 | logs: (wx.getStorageSync('logs') || []).map(function (log) { 9 | return util.formatTime(new Date(log)) 10 | }) 11 | }) 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /client/pages/logs/logs.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "查看启动日志" 3 | } -------------------------------------------------------------------------------- /client/pages/logs/logs.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{index + 1}}. {{log}} 5 | 6 | 7 | -------------------------------------------------------------------------------- /client/pages/logs/logs.wxss: -------------------------------------------------------------------------------- 1 | .log-list { 2 | display: flex; 3 | flex-direction: column; 4 | padding: 40rpx; 5 | } 6 | .log-item { 7 | margin: 10rpx; 8 | } 9 | -------------------------------------------------------------------------------- /client/utils/qiniuUploader.js: -------------------------------------------------------------------------------- 1 | // created by gpake 2 | (function() { 3 | 4 | var config = { 5 | qiniuRegion: '', 6 | qiniuImageURLPrefix: '', 7 | qiniuUploadToken: '', 8 | qiniuUploadTokenURL: '', 9 | qiniuUploadTokenFunction: null 10 | } 11 | 12 | module.exports = { 13 | init: init, 14 | upload: upload, 15 | } 16 | 17 | // 在整个程序生命周期中,只需要 init 一次即可 18 | // 如果需要变更参数,再调用 init 即可 19 | function init(options) { 20 | config = { 21 | qiniuRegion: '', 22 | qiniuImageURLPrefix: '', 23 | qiniuUploadToken: '', 24 | qiniuUploadTokenURL: '', 25 | qiniuUploadTokenFunction: null 26 | }; 27 | updateConfigWithOptions(options); 28 | } 29 | 30 | function updateConfigWithOptions(options) { 31 | if (options.region) { 32 | config.qiniuRegion = options.region; 33 | } else { 34 | console.error('qiniu uploader need your bucket region'); 35 | } 36 | if (options.uptoken) { 37 | config.qiniuUploadToken = options.uptoken; 38 | } else if (options.uptokenURL) { 39 | config.qiniuUploadTokenURL = options.uptokenURL; 40 | } else if(options.uptokenFunc) { 41 | config.qiniuUploadTokenFunction = options.uptokenFunc; 42 | } 43 | if (options.domain) { 44 | config.qiniuImageURLPrefix = options.domain; 45 | } 46 | } 47 | 48 | function upload(filePath, success, fail, options) { 49 | if (null == filePath) { 50 | console.error('qiniu uploader need filePath to upload'); 51 | return; 52 | } 53 | if (options) { 54 | init(options); 55 | } 56 | if (config.qiniuUploadToken) { 57 | doUpload(filePath, success, fail, options); 58 | } else if (config.qiniuUploadTokenURL) { 59 | getQiniuToken(function() { 60 | doUpload(filePath, success, fail, options); 61 | }); 62 | } else if (config.qiniuUploadTokenFunction) { 63 | config.qiniuUploadToken = config.qiniuUploadTokenFunction(); 64 | } else { 65 | console.error('qiniu uploader need one of [uptoken, uptokenURL, uptokenFunc]'); 66 | return; 67 | } 68 | } 69 | 70 | function doUpload(filePath, success, fail, options) { 71 | var url = uploadURLFromRegionCode(config.qiniuRegion); 72 | var fileName = filePath.split('//')[1]; 73 | if (options && options.key) { 74 | fileName = options.key; 75 | } 76 | var formData = { 77 | 'token': config.qiniuUploadToken, 78 | 'key': fileName 79 | }; 80 | console.log('url:', url, 'filePath:', filePath, 'formData:', formData) 81 | wx.uploadFile({ 82 | url: url, 83 | filePath: filePath, 84 | name: 'file', 85 | formData: formData, 86 | success: function (res) { 87 | var dataString = res.data 88 | var dataObject = JSON.parse(dataString); 89 | //do something 90 | var imageUrl = config.qiniuImageURLPrefix + dataObject.key; 91 | dataObject.imageURL = imageUrl; 92 | console.log(dataObject); 93 | if (success) { 94 | success(dataObject); 95 | } 96 | }, 97 | fail: function (error) { 98 | console.log(error); 99 | if (fail) { 100 | fail(error); 101 | } 102 | } 103 | }) 104 | } 105 | 106 | function getQiniuToken(callback) { 107 | wx.request({ 108 | url: config.qiniuUploadTokenURL, 109 | success: function (res) { 110 | var token = res.data.uptoken; 111 | config.qiniuUploadToken = token; 112 | if (callback) { 113 | callback(); 114 | } 115 | }, 116 | fail: function (error) { 117 | console.log(error); 118 | } 119 | }) 120 | } 121 | 122 | function uploadURLFromRegionCode(code) { 123 | var uploadURL = null; 124 | switch(code) { 125 | case 'ECN': uploadURL = 'https://up.qbox.me'; break; 126 | case 'NCN': uploadURL = 'https://up-z1.qbox.me'; break; 127 | case 'SCN': uploadURL = 'https://up-z2.qbox.me'; break; 128 | case 'NA': uploadURL = 'https://up-na0.qbox.me'; break; 129 | default: console.error('please make the region is with one of [ECN, SCN, NCN, NA]'); 130 | } 131 | return uploadURL; 132 | } 133 | 134 | })(); -------------------------------------------------------------------------------- /client/utils/util.js: -------------------------------------------------------------------------------- 1 | function formatTime(date) { 2 | var year = date.getFullYear() 3 | var month = date.getMonth() + 1 4 | var day = date.getDate() 5 | 6 | var hour = date.getHours() 7 | var minute = date.getMinutes() 8 | var second = date.getSeconds(); 9 | 10 | 11 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 12 | } 13 | 14 | function formatNumber(n) { 15 | n = n.toString() 16 | return n[1] ? n : '0' + n 17 | } 18 | 19 | module.exports = { 20 | formatTime: formatTime 21 | } 22 | -------------------------------------------------------------------------------- /server/qiniuTokenServer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 作者:刘焱旺 yw@getweapp.com 3 | * 答疑交流QQ群:499859691 4 | */ 5 | 6 | // api服务 7 | const Restify = require('restify') 8 | const Server = Restify.createServer() 9 | Server.use(Restify.queryParser()) 10 | Server.use(Restify.bodyParser()) 11 | 12 | // qiniu 13 | import qiniu from 'qiniu' 14 | 15 | // 监听端口号 16 | const PORT = 9885 17 | 18 | qiniu.conf.ACCESS_KEY = 'xxxx'; // 你的七牛帐户的ACCESS_KEY 19 | qiniu.conf.SECRET_KEY = 'xxxx'; // 你的七牛帐户的SECRET_KEY 20 | 21 | const bucket = 'xxxx'; // 你的七牛帐户的bucket 22 | 23 | /********** 业务处理开始 **********/ 24 | 25 | // 获取uptoken 26 | Server.get('/uptoken', (req, res) => { 27 | const putPolicy = new qiniu.rs.PutPolicy(bucket) 28 | const uptoken = putPolicy.token() 29 | console.log('get token:', uptoken) 30 | res.send({ 31 | code: 0, 32 | uptoken: uptoken 33 | }) 34 | }) 35 | 36 | /********** 业务处理结束 **********/ 37 | 38 | // 监听端口开启api服务 39 | Server.listen(PORT, () => { 40 | console.log('开启服务器,端口号:', PORT) 41 | }) 42 | --------------------------------------------------------------------------------