- 开发者工具调试没问题,手机上预览以及真机调试调用云函数均失败?
[图片] 如图,在真机调试中显示wx.cloud.uploadFile调用失败。预览时在手机上操作同样也失败了。但是在开发者工具中编译后可以调用成功,这是什么原因?
2020-05-16 - 循环内的wx.cloud.uploadFile返回值无法和index同步怎么办?
搞了好几天了解决不了,有没有大神为我解答? 云开发上传多个图片,用户选择多个图片,上传时显示进度,上传完成后图片按照当时的选择顺序显示。 代码大致结构如下: [代码]data: {[代码][代码] [代码][代码]imagesPreview: [][代码][代码]},[代码][代码]postImages: [代码][代码]function[代码][代码]() {[代码][代码] [代码][代码]wx.chooseImage({[代码][代码] [代码][代码]//选择9张图片[代码][代码] [代码][代码]success: [代码][代码]function[代码][代码](res) {[代码][代码] [代码][代码]var[代码] [代码]filePaths = res.filePaths[代码][代码] [代码] [代码] [代码][代码]//把本地临时路径放在集合里[代码][代码] [代码][代码]for[代码] [代码]([代码][代码]var[代码] [代码]i [代码][代码]in[代码] [代码]filePaths) {[代码][代码] [代码][代码]var[代码] [代码]imagesTemp = { [代码][代码]'filePath'[代码][代码]: filePaths[i], [代码][代码]'fileID'[代码][代码]: [代码][代码]''[代码][代码], [代码][代码]'progress'[代码][代码]: 0 }[代码][代码] [代码][代码]that.data.imagesPreview.push(imagesTemp)[代码][代码] [代码][代码]}[代码] [代码] [代码][代码]//再一次循环,根据上传返回结果依次改变集合内的对应值[代码][代码] [代码][代码]for[代码] [代码]([代码][代码]var[代码] [代码]j [代码][代码]in[代码] [代码]filePaths) {[代码][代码] [代码][代码]var[代码] [代码]filePath = that.data.imagesPreview[j].filePath[代码][代码] [代码][代码]var[代码] [代码]fileName = common.getUniqueFileName(app.globalData.userInfo._id)[代码][代码] [代码][代码]var[代码] [代码]cloudPath = fileName + filePath.match(/\.[^.]+?$/)[0][代码][代码] [代码][代码]var[代码] [代码]uploadTask = wx.cloud.uploadFile({[代码][代码] //[代码][代码]...[代码][代码] [代码][代码]success: res => {[代码][代码] [代码][代码]that.data.imagesPreview[j].fileID = res.fileID[代码][代码] [代码][代码]that.setData({[代码][代码] [代码][代码]imagesPreview: that.data.imagesPreview[代码][代码] [代码][代码]})[代码][代码] [代码][代码]}[代码][代码] [代码][代码]})[代码] [代码] [代码][代码]uploadTask.onProgressUpdate((res) => {[代码][代码] [代码][代码]that.data.imagesPreview[j].progress = res.progress[代码][代码] [代码][代码]that.setData({[代码][代码] [代码][代码]imagesPreview: that.data.imagesPreview[代码][代码] [代码][代码]})[代码][代码] [代码][代码]})[代码][代码] [代码][代码]}[代码][代码] [代码][代码]},[代码][代码] [代码][代码]})[代码][代码]},[代码] 比如选了3张图片 [代码]imagePreview = [[代码] [代码]{[代码][代码]'filePath'[代码][代码]:[代码][代码]'地址1'[代码][代码],[代码][代码]'fileID'[代码][代码]:[代码][代码]''[代码][代码],[代码][代码]'progress'[代码][代码]:0},[代码] [代码]{[代码][代码]'filePath'[代码][代码]:[代码][代码]'地址2'[代码][代码],[代码][代码]'fileID'[代码][代码]:[代码][代码]''[代码][代码],[代码][代码]'progress'[代码][代码]:0},[代码] [代码]{[代码][代码]'filePath'[代码][代码]:[代码][代码]'地址3'[代码][代码],[代码][代码]'fileID'[代码][代码]:[代码][代码]''[代码][代码],[代码][代码]'progress'[代码][代码]:0}[代码] [代码]][代码] 当准备上传这3张图片时,进度progress只会在最后一个{'filePath':'地址3','fileID':'','progress':0}里面更新,返回的fileID也是。 查了遍console.log,应该是由于上传文件是异步处理,遍历完了之后uploadFile结果还没返回,并且j停留在集合最后一个。 所以问题来了,要做到fileID和progress都能在集合内对应的位置更新该怎么办?
2019-11-05 - wx.cloud.uploadFile何时返回调用成功?遇到一个很奇怪的问题
首先,上代码片段 [代码]release(e){[代码][代码] [代码][代码]var[代码] [代码]imageUrl = [];[代码][代码] [代码][代码]var[代码] [代码]temp = [];[代码][代码] [代码][代码]for[代码] [代码]([代码][代码]var[代码] [代码]i = 0; i < [代码][代码]this[代码][代码].data.filepath.length; i++) {[代码][代码] [代码][代码]wx.cloud.uploadFile({[代码][代码] [代码][代码]cloudPath: [代码][代码]this[代码][代码].data.cloudpath[i], [代码][代码]// 上传至云端的路径[代码][代码] [代码][代码]filePath: [代码][代码]this[代码][代码].data.filepath[i], [代码][代码]// 小程序临时文件路径[代码][代码] [代码][代码]success: res => {[代码][代码] [代码][代码]imageUrl = imageUrl.concat(res.fileID)[代码][代码] [代码][代码]temp = res.fileID[代码][代码] [代码][代码]console.log([代码][代码]'imageUrl'[代码][代码], imageUrl)[代码][代码] [代码][代码]}[代码][代码] [代码][代码]})[代码][代码] [代码][代码]}[代码][代码] [代码][代码]console.log([代码][代码]'imageUrl aaaa'[代码][代码], imageUrl)[代码][代码] [代码][代码]console.log([代码][代码]'temp bbbb'[代码][代码], temp)[代码] [代码] [代码][代码]db.collection([代码][代码]'emall'[代码][代码]).add({[代码][代码] [代码][代码]data: {[代码][代码] [代码][代码]title: [代码][代码]this[代码][代码].data.location + [代码][代码]'出租'[代码][代码],[代码][代码] [代码][代码]price: [代码][代码]this[代码][代码].data.price + [代码][代码]'/月'[代码][代码],[代码][代码] [代码][代码]image: imageUrl,[代码][代码] [代码][代码]inDate: [代码][代码]this[代码][代码].data.date,[代码][代码] [代码][代码]pictureCnt: i,[代码][代码] [代码][代码]},[代码][代码] [代码][代码]success: res2 => {[代码][代码] [代码][代码]console.log([代码][代码]'文件上传成功'[代码][代码], res2)[代码][代码] [代码][代码]wx.showToast({[代码][代码] [代码][代码]title: [代码][代码]'新增成功'[代码][代码],[代码][代码] [代码][代码]})[代码][代码] [代码][代码]},[代码][代码] [代码][代码]fail: err => {[代码][代码] [代码][代码]console.error([代码][代码]'error'[代码][代码], err)[代码][代码] [代码][代码]}[代码][代码] [代码][代码]})[代码][代码]},[代码]背景介绍: 我有一个商品信息需要上传到数据库,这个商品有多张图片来描述; 在上面的release接口中,有一个for循环,实现上传多张图片到腾讯云,把上传成功的fileid用一个数组记录下来 所有图片上传成功后,将这些腾讯云的图片路径和商品信息保存在一个数据库记录中 遇到的问题 实际调试时,发现程序执行到wx.cloud.uploadFile时,并没有等待这个数据是否上传成功,而是继续向下执行了,因此会发现先打印了 [代码]imageUrl aaaa[代码][代码]temp bbbb[代码]然后会接着打印,以及真正的云端路劲地址 [代码]imageUrl[代码]疑惑的地方 在函数release中调用wx.cloud.uploadFile的时候,它并不知道什么时候上传成功,就会直接跳转到后面的函数执行,那有什么办法能够确认wx.cloud.uploadFile函数执行成功后再继续执行release函数后面的语句吗? 因为我是嵌入式C语言出生,小程序以及js语言完全属于自学,这样的用法感觉好奇怪,一个函数里面像是发生了线程调度,被打断后,继续执行这个函数后面的操作,这是什么逻辑操作?还是很多前端部分的语言都是这个德行?按照C语言的执行流程,这个时候release函数就应该block在这边,等待wx.cloud.uploadFile执行完成之后,再继续执行;或者你也可以引发一次线程调度,执行其他的部分,但是release函数肯定是被block住的。 等图片上传成功后,又返回到wx.cloud.uploadFile的success中继续执行,可是给我感觉在图片上传成功之前,release整个函数都应该执行结束了,然后微信小程序还会继续自行跳转到这个函数中来执行,这个又是什么神操作?那么release这个函数的生命周期究竟是多少? 难怪之前在网上看到有人用了递归的方法来做wx.cloud.uploadFile,当时还没完全理解别人这样做的意义何在,今天调试下来感觉应该就是现在反馈的问题带来的处理,可是循环比递归理解起来简单多了呀
2019-08-19 - 微信小程序开发技巧总结(二) -- 文件的选取、移动、上传和下载
微信小程序开发技巧总结(二) – 文件的选取、移动、上传和下载 1.不同类型文件的选取 1.1 常用的图片 视频 对于大部分开发者来说,需要上传的文件形式主要为图片,微信为此提供了接口。 [代码]wx.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success (res) { // tempFilePath可以作为img标签的src属性显示图片 const tempFilePaths = res.tempFilePaths } }) [代码] 其次为视频文件的选取,微信也为此提供了接口。 [代码]wx.chooseVideo({ sourceType: ['album','camera'], maxDuration: 60, //视频长度 单位 s camera: 'back', //选取前置 摄像 还是 后置 摄像 success(res) { console.log(res.tempFilePath) } }) [代码] 也为其提供了视频和图片的二合一接口,这个接口不建议调用,图片和视频的上传建议区分开。 [代码]wx.chooseMedia({ count: 9, mediaType: ['image','video'], sourceType: ['album', 'camera'], maxDuration: 30, camera: 'back', success(res) { console.log(res.tempFilePath)con console.log(res.size) } }) [代码] 这几个接口调用成功的回调函数中,都返回的是文件在文件在本机中的路径。 [代码]res.tempFilePath [代码] 这是一个 数组,存放着选择的所有文件的路径,用于上传。 1.2 其余形式各种文档 那么如果是想要在小程序中上传 doc、pdf、ppt 等类型的文件怎么处理?首先要注意的是微信小程序并没有给用户提供文件管理器接口。 开发者:我想要个文件管理器接口! 官方:不,你不想 聪明的开发者他没有办法,只能另辟蹊径。微信提供了一个选择客户端会话文件的方法。 [代码]wx.chooseMessageFile({ success(res){ console.log(res.tempFilePath) } }) [代码] 与上面两个接口相同,返回的也是文件在本地的存储路径,但是不同的是,这个接口可以选取全部的文件类型。 开发者如果想要上传非图片和视频内容的话,需要两步走。 打开微信文件传输助手,将想要上传的文件发送到文件传输助手 在小程序中调用这个接口,选择文件传输助手,从会话中选择想要上传的文件。 [图片] [图片] 2.文件的上传 2.1 uploadFile方法 所有的文件都是以字节流的形式进行上传,所以上传形式并没有什么本质区别,都是调用相应的接口进行上传。 小程序端写法如下: [代码]wx.uploadFile({ url: '你的服务器函数地址', //仅为示例,非真实的接口地址 filePath: '需要上传的文件路径', //res.tempFilepaths name: 'file', // 文件对应的key ,默认 为 file formData: { 'user': 'test' }, //上传额外携带的参数 success (res){ const data = res.data //do something } }) [代码] 2.2 服务器端如何处理上传的文件 服务端如何接受文件的上传?仅展示Java方式(SpringBoot 框架) [代码]@Controller @ResponseBody public class FileController { //文件上传控制类,是核心配置类,Win <->Linux @RequestMapping(value = "/upload/images") public String uploadimages(HttpServletRequest request,@RequestParam("file") MultipartFile file, @RequestParam("user") String user) throws IOException { //更换服务器,这个值也需要修改 //图片上传写法 //type 是上传图片的类型 if(!file.isEmpty()){ //文件不为空 //String path = "E:"+File.separator+"images"+File.separator+type; // this is windows method String path = "/share"+File.separator+"images"+File.separator+type; // this is Linux method String filename = file.getOriginalFilename(); File filepath = new File(path,filename);//新建文件存储路径 System.out.println(filepath); if(!filepath.getParentFile().mkdirs()){ filepath.getParentFile().mkdirs(); } file.transferTo(new File(path+File.separator+filename)); //想要返回可直接访问的链接还要配置 映射,具体请看下面链接 return "你的IP地址"+"/images/"+type+"/"+filename; }else { return "error"; } } } [代码] 配置访问映射 文件访问映射 2.3 云开发文件上传 微信小程序支持云开发,其文件上传接口有一些差异,但是不需要自己再构建后台。 [代码]wx.cloud.uploadFile({ cloudPath: 'file/' + '你的文件名字(带格式后缀)', // 在云端存储的路径 filePath: '', // 就是选择文件返回的路径 }).then(res => { // get resource ID console.log(res.fileID) }).catch(error => { // handle error }) [代码] 我们可以根据返回的fileID 置换 真实的文件访问地址。 其置换方式参见官方文档: [代码]wx.cloud.getTempFileURL({ fileList: ['cloud://xxx', 'cloud://yyy'], success: res => { // get temp file URL console.log(res.fileList) }, fail: err => { // handle error } }) [代码] TIPS:关于云开发文件上传的建议 如果没有保密需求,为了方便后续开发,存储到数据库中的最好是可以直接访问的文件链接。 置换真实文件地址,不要每次上传一次文件就置换一次,先把返回的fileID 存放在数组中,到该事务所有上传完成后,再使用fileID 数组置换真实文件访问链接数组。 要考虑文件名重复的可能,建议使用时间戳在 wx.cloud.uploadFile 中的 cloudPath 中对存储到云环境中的文件命名进行格式化。 总的来说就是先上传文件,再向数据库中写入记录。 2.4 多文件同时上传的处理方式 uploadFile 每次只能上传一个文件 如何处理这个问题? A.不考虑文件的上传次序问题,可以采用遍历上传的方式,采用精确的时间戳和遍历index对文件名进行格式化。通过定时触发检测函数判断是否全部上传完成。这种方式考虑的是并发能力。 [代码]upSeveralfiles() { wx.showLoading({ title: '上传中~', mask: true }) var that = this; var timecode = sev.vcode(new Date()); // 这是时间戳编码函数 var files = this.data.fileList; // 这是 选择文件中返回的 res.tempFilePath 数组 var len = files.length; var i = 0; for (i = 0; i < len; i++) { var str = files[i].name; wx.cloud.uploadFile({ cloudPath: 'file/' + '(' + sev.getformatTime(new Date()) + ')' + str, filePath: files[i].path, success(res) { console.log(res) that.setData({ cloudlist: that.data.cloudlist.concat([res.fileID]), }) // cloudlist 是存放 文件链接置换id 的数组 , 非云开发存储的就是真实可访问的链接数组 // 如果使用的不是云开发 那么 可以返回真实的 访问地址 }, fail(res) { console.log(res) } }) } // 使用定时器检测文件是否全部上传完成 , 并 判断是否进行下一步 操作 var timer = setInterval(function () { if (that.data.cloudlist.length == len) { // 只有全部上传成功了 长度才会相等 clearInterval(timer); // 继续执行下一步 ,根据 cloudlist 置换真实地址 并存放到数据库 // 如果使用的非云开发,那么就继续执行 存储至数据库的操作 } }, 1000) } [代码] 补充文件编码函数 sev.js 中的根据时间编码部分 , 可以根据实际流量自定义。 [代码]function getformatTime(date) { var year = date.getFullYear() var month = date.getMonth() + 1 var day = date.getDate() var hour = date.getHours() var minute = date.getMinutes() var second = date.getSeconds() return [year, month, day].map(formatNumber).join('-'); }; [代码] B.考虑文件的上传次序问题,采用回调方式进行文件上传(更推荐使用这种方式) [代码]data: { fileList: [], realList: [],//云端地址链接列表 fileid: 0, }, upSeveralfiles() { var that = this; var files = this.data.fileList; // 这是 选择文件中返回的 res.tempFilePath 数组 var len = files.length; var uid = this.data.fileid; wx.uploadFile({ url: '你的服务器文件接收函数请求地址', name: 'file', filePath: files[uid], header: { "Content-Type": "multipart/form-data" }, success(res) { that.setData({ fileid: uid + 1, realList: that.data.realList.concat([res.data]) }, () => { if (that.data.fileid == len) { // 上传完成 ,执行下一步操作 } else { //上传完一个文件 递归执行 下次上传 that.upSeveralfiles(); } }) }, fail(res) { console.log(res.data) } }) }, [代码] 以上是提供的两种思路 , 无论是不是云开发 , 两种思路都是共通的,适用于多文件上传. 文件的下载 这个地方唯一值得注意的是云开发的一种下载方式 可以通过fileID进行download , 当然只能下载存储在自己云环境中的文件. [代码]wx.cloud.downloadFile({ fileID: '', success: res => { console.log(res.tempFilePath) }, fail: err => { } }) [代码] [代码]wx.downloadFile({ url: '', //仅为示例,并非真实的资源 success (res) { //res.tempFilePath }) [代码] 下载进度监控 , 用于下载进度条绘制等功能实现 [代码]const downloadTask = wx.cloud.downloadFile({ *** }) // wx.downloadFile 同理 downloadTask.onProgressUpdate((res) => { //res.progress 为下载进度 }) [代码] 下载下来的文件支持直接打开,就像是在微信聊天中打开一样,需要下载插件。 其使用方式为: [代码]wx.openDocument({ filePath: res.tempFilePath //为文件路径 非数组 , 可使用回调函数 success 等 }) [代码] 文件的移动 这个一般情况下是用不到的, 也不建议使用移动文件的方法作为功能实现手段 ,必然有更好的替代方式,比如修改数据库路径 和 真实文件路径的映射, 效率更高一些. 这里仅讲云开发移动文件方式。 [代码]const cloud = require('wx-server-sdk') const fs = require('fs') const path = require('path') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) exports.main = async (event, context) => { const fileStream = fs.createReadStream(path.join(__dirname, 'demo.jpg')) //这个可以读取 云存储 中的文件 , 所谓删除 就是复制 然后 删除原位置文件 return await cloud.uploadFile({ cloudPath: 'demo.jpg', fileContent: fileStream, }) } [代码] 具体开发文档 建议在数据库中修改映射路径最好。 需要小程序开发的请联系我QQ : 1025584691
2020-02-17