- 【物流助手】小程序下单,但是运单号是使用第三方平台生成的,还能调用物流助手的运单轨迹接口吗?
问题1:调用【物流助手】是否意味着运单号必须从mp后台获得 问题2:通过小程序下单,从其他平台获得运单号,能否使用物流助手接口返回运单轨迹
2020-09-10 - 如何”加快“内容安全接口imgSecCheck的云调用速度
简介 使用云开发来实现内容安全检测比较方便,并且对个人小程序来说是零成本。但是也有一些问题 问题一:通过云函数调用图片安全接口时,如果直接传入Buffer类型的图片数据,真机可能会返回-404012错误。 这个问题可以先将图片上传至云存储,再在云函数中下载图片,然后调用内容安全接口,可以避免此问题,并且实测速度较直接传入Buffer有所提升。 内容安全接口的图片大小限制为1M。 为避免出现这个问题,可以使用Canvas压缩图片。或调用获取本机图片的接口时默认选择压缩的图片,也可以规避大部分问题。 云函数的访问速度较慢(尤其是小程序启动后的第一次调用)。简单看了一下,用云函数调用文本安全时,一般是0.5-0.6s,还行。而调用图片安全时,用传入Buffer数据的方法检测一个500K的图片大约需5s;如果用先上传云存储,再调用云函数检测的方法,上传需大约0.7s,调云函数检测需2.5s,还是需要3s+,可能会影响一定的用户体验。 下面主要介绍一下如何“减少”内容安全的请求时间,这个方法在其他地方也可以用。 基本方法是在用户点击提交前进行内容安全检测,将请求结果缓存为一个promise对象,然后在用户提交时使用之前缓存的promise的[代码]then[代码]方法获取到检测结果。如果这里看明白了,后面的就不用看了,可以自己去实现了。 有些代码没有简化了,所以看起来可能有点复杂,所以可以只看文字注释。 简单的示例代码 图片安全检测 首先将图片安全检测封装为一个Promise类型的函数 [代码]async function imgSecCheck({path}){ // async关键词,声明返回Promise let cloudPath = "images/avatars/"+ path.replace(/[\/\\:]/g, "_"); // 首先上传云存储 let {fileID} = await wx.cloud.uploadFile({ cloudPath, filePath: path }); // 调用云函数 let res = await wx.cloud.callFunction({ // 这里的参数结构要根据你写的云函数来具体确定, // 该示例代码所对应的云函数代码在后文有给出 name: "openapi", data:{ name:"security.imgSecCheck", data:{ fileID } } }); return res.result; } [代码] 现在要在一个页面实现图片安全检测 在用户选择了图片后,获取到了图片的本地地址[代码]path[代码],此时调用函数提前检测,并缓存返回的promise对象 [代码]let cache_promise = imgSecCheck({ path }) [代码] 最后在用户提交图片时,使用[代码]then[代码]来获取前面缓存的结果。像这样在用户提交前进行检测,可以减少一点用户的等待时间,理想状态下用户等待的检测时间可以为0s。 [代码]cache_promise.then(res=>{ if(res.errCode==87014){ // 图片有问题,提示用户 }else{ // 图片没有问题,执行其他逻辑 } }) [代码] 文本安全检测 与图片检测类似,也可以用上面相同的方法来实现“加速” 首先将文本安全检测封装为一个Promise类型的函数 [代码]async function msgSecCheck({content}){ // async关键词,声明返回Promise let res = await wx.cloud.callFunction({ // 这里的参数结构要根据你写的云函数来具体确定, // 该示例代码所对应的云函数代码在后文有给出 name: "openapi", data:{ name:"security.msgSecCheck", data:{ content } } }); return res.result; } [代码] 可以在用户实时输入的时候,进行提前检测,于是将该函数绑定到[代码]input[代码]组件的输入事件[代码]bindinput[代码]回调上,或者绑定到输入框的失焦事件[代码]bindblur[代码]回调上,根据不同需求来选择即可。 [代码]<!--wxml--> <input bindinput="preCheck"/> <!--或者用下面这个绑定到blur回调上--> <input bindblur="preCheck"/> // js Page({ preCheck({detail:{value}}){ // 缓存检测结果 this.cache_promise = msgSecCheck({ content: value }); } }) [代码] 如果绑定到[代码]bindinput[代码],函数会在短时间被多次回调,此时需要对上面的[代码]msgSecCheck[代码]进行修饰,让其两次执行间必须间隔1s,且最后一次的回调一定执行。 可以使用限频函数[代码]throttle[代码]对其进行修饰: [代码]msgSecCheck = throttle(msgSecCheck, 1000, {} ); [代码] 这里用的的[代码]throttle[代码]函数取自微信官方的一个代码片段 [代码]function throttle(func, wait, options) { var context = void 0; var args = void 0; var result = void 0; var timeout = null; var previous = 0; if (!options) options = {}; var later = function later() { previous = options.leading === false ? 0 : Date.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function () { var now = Date.now(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > wait) { clearTimeout(timeout); timeout = null; previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; }; }; [代码] 附较完整的代码 图片安全检测 [代码]const app = getApp(); Page({ async _checkImg({path}){ // 上传图片至云存储 let cloudPath = "images/avatars/"+ path.replace(/[\/\\:]/g, "_"); let res = await wx.cloud.uploadFile({ cloudPath, filePath: path }); let {fileID} = res; // 调用云函数的图片安全检测接口,该函数返回一个Promise return app.openapi("security.imgSecCheck")({fileID}); }, checkImg({path}){ // 查看是否有缓存,有则直接返回缓存的promise if(this.promise&&path==this.tmp_path) return this.promise; // 没有则请求,并缓存请求的结果 this.promise = this._checkImg({path}); this.tmp_path = path; this.promise.then(res=>{ console.log(res); if(res.errCode==87014){ wx.showToast({ title:rich_message,icon: "none",duration:5000 }) } }); return this.promise; }, afterSelectImg({path}){ // 选择图片后 this.checkImg({path}); }, onSubmit(){ // 提交时 this.checkImg().then(res=>{ if(res.errCode==0){ //没有问题,执行其他逻辑 }else if(res.errCode==87014){ wx.showModal({ content:“图片有敏感内容”,showCancel: false }) } }); } }) [代码] 文本安全检测 [代码]const app = getApp(); // 限频函数的一个实现,来自微信官方的一个代码片段 function throttle(func, wait, options) { var context = void 0; var args = void 0; var result = void 0; var timeout = null; var previous = 0; if (!options) options = {}; var later = function later() { previous = options.leading === false ? 0 : Date.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function () { var now = Date.now(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > wait) { clearTimeout(timeout); timeout = null; previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; }; }; function msgSecCheck({content=""}){ // 判断是否有缓存 if(this.tmp_promise&&this.tmp_content==content) return this.tmp_promise; //有则直接返回 //没有缓存,则进行请求,并以promise类型缓存请求 this.tmp_promise = app.openapi("security.msgSecCheck")({content}); this.tmp_content = content; this.tmp_promise.then(res=>{ if(res.errCode==87014){ wx.showToast({ title: “有敏感词汇”,icon:"none",duration:4000 }) } }) return this.tmp_promise; } Page({ throttledMsgSecCheck: throttle( msgSecCheck, 1000, {} ),//被限频的函数,用于input事件的回调中 msgSecCheck, onInput({detail:{value}}){ // input事件的回调 this.throttledMsgSecCheck({content: value}); }, onSubmit({detail:{value}}){ wx.showLoading({ title: '检查内容中...' }) this.msgSecCheck({content: value.name}).then(res=>{ if(res.errCode==0){ wx.showLoading({ title: '正在提交' }) //执行提交逻辑 }else{ // 检测到敏感词 wx.hideLoading(); wx.showModal({ content:“有敏感词汇”, showCancel:false }) } }) } }) [代码] 本地代码的封装 [代码]/** app.js 将云调用代码简单封装了一下 **/ App({ openapi(name){ // 函数柯里化,调用时写起来方便 return ({success, fail, complete, ...data})=>{ return this.callOpenapi({name, data, success,fail, complete}); } }, callOpenapi({name, data, success, fail, complete}){ // 调用名为openapi的云函数 return this.callCloudapi({name:"openapi", data:{name, data}, success, fail, complete}); }, callCloudapi({name, data, success, fail, complete}){ return new Promise((resolve, reject)=>{ return wx.cloud.callFunction({name, data, success:res=>{ // 只需要 res.result 中的数据 success&&success(res.result); resolve(res.result); complete&&complete(res.result); }, fail:e=>{ fail&&fail(e); reject(e); complete&&complete(e); } }); }); } }); [代码] 云函数代码 [代码]// 云函数名: openapi const cloud = require('wx-server-sdk') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV}) exports.main = async (event, context) => { console.log("调用云函数openapi, 参数event:", event); let {name, data} = event; switch (event.name) { case "security.msgSecCheck":{ try{ console.log("检查文本安全, 参数:", data); var res = await cloud.openapi.security.msgSecCheck(data); console.log("返回结果: ", res); return res; }catch(e){ return e; } } case "security.imgSecCheck":{ try{ console.log("检查图片安全, 参数:", data); if(data.media) var value = Buffer.from(data.media); else if(data.fileID){ var {fileID} = data; var res = await cloud.downloadFile({fileID}); var value = res.fileContent; } var res = await cloud.openapi.security.imgSecCheck({ media:{ contentType:"image/png", value } }); console.log("返回结果: ", res); return res; }catch(e){ return e; } } } } [代码] 官方有时会检测去小程序的内容安全接口是不是完善。为了避免接口错误导致误判,可以保留上面云函数中的console日志和一周内上传至云储存的图片留作证据
2020-07-16 - 小程序订阅消息开发指南
2019年10月12日微信开放了小程序订阅消息的功能。按官方的说法,目前的模板消息在实现小程序服务闭环上存在缺陷: 1. 部分开发者在用户无预期或未进行服务的情况下发送与用户无关的消息,对用户产生了骚扰;2. 模板消息需在用户访问小程序后的 7 天内下发,不能满足部分业务的时间要求模板消息确实存在上述的硬伤,不利于小程序的用户留存和用户体验。为了解决这些问题,微信官方推出了用户订阅消息功能。我在微慕专业版上加了订阅消息的功能,并验证了这个功能。这个功能是否能都达到官方的预期,这个我感觉不那么乐观。这里我先说我的感受:目前的订阅消息还不完善,后续还有很大的优化空间。 目前,官方只开放了“一次性订阅消息”,尚未开放“长期性订阅消息”,因此我只尝试了“一次性订阅消息”。 一次性订阅消息:用于解决用户使用小程序后,后续服务环节的通知问题。用户自主订阅后,开发者可不限时间地下发一条对应的服务消息;每条消息可单独订阅或退订。 订阅消息推送位置:服务通知 订阅消息下发条件:用户自主订阅 订阅消息卡片跳转能力:点击查看详情可跳转至该小程序的页面 以下我简单说明订阅消息的开发过程和使用体验。 一.订阅消息的开发1.获取订阅消息的模板ID 在微信小程序的管理后台,在左侧“功能”菜单,选择“订阅消息”,然后点击“添加” [图片] 然后选择你需要的消息模板,并配置关键词。 [图片] 配置完成后,如下图所示。 [图片] 值得关注的是,在配置好的模板详情页面里的“详细内容”很重要,这个就是开发订阅消息时需要遵循的消息格式,这个格式和模板消息有细微的差别 根据微慕小程序的需要,我选用了“新的评论提醒”和“内容更新提醒”这两个消息模版。前者用于提醒发表话题或文章的作者,有新的话题或文章评论,增强作者与读者之间的交流互动;后者是提醒订阅用户,小程序有新的文章发布,引导用户回归小程序。 订阅消息申请模板的时候,需要选择所属类目,只能选择当前小程序相关的类目模板,对于模板消息不需要选择对应类目。如果删除小程序类目,就会把订阅消息模板一起删除。因此删除类目要小心谨慎。 [图片] 2.触发用户订阅,获取下发的权限 触发用户订阅,微信小程序提供的api是: [代码]wx.requestSubscribeMessage[代码],用户发生点击行为或者发起支付回调后,才可以调起订阅消息界面。 注意:微信小程序开发工具尚不支持此功能,在开发工具触发订阅的api,会提示: requestSubscribeMessage:fail 开发者工具暂时不支持此 API 调试,请使用真机进行开发 调用api的代码示例如下: [代码]wx.requestSubscribeMessage({[代码] [代码]tmplIds: ["模板A","模板B"],[代码] [代码]success: function (res) {[代码] [代码]//成功[代码] [代码]},[代码] [代码]fail(err) {[代码] [代码]//失败[代码] [代码]console.error(err);[代码] [代码]}[代码] [代码]})[代码] wx.requestSubscribeMessage(Object object) 的回调函数[代码]object.success [代码]参数有两个:errMsg和TEMPLATE_ID; 接口调用成功时errMsg值为’requestSubscribeMessage:ok’。TEMPLATE_ID是动态的键,即模板id,值包括’accept’、’reject’、’ban’。’accept’表示用户同意订阅该条id对应的模板消息,’reject’表示用户拒绝订阅该条id对应的模板消息,’ban’表示已被后台封禁。例如 { errMsg: “requestSubscribeMessage:ok”, zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE: “accept”} 表示用户同意订阅zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE这条消息。 个人觉得这个动态键不是特别合理,代码处理起来有些麻烦,如果改成静态键的json格式比较方便处理,例如: [代码]{[代码] [代码] errMsg:"requestSubscribeMessage:ok",[代码] [代码] result: [[代码] [代码] { templateId:"zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE",[代码] [代码]status:"accept"[代码] [代码]}[代码] [代码] ][代码] [代码]}[代码] 在手机上调用此api方法会调出订阅消息的界面,如下图所示: [图片] 关于这个订阅消息的授权有几点要注意: 1) 在确认提示框里,如果用户选择“取消”表示拒绝(取消)订阅消息,选择“允许”表示用户订阅一次消息。 2) 如果用户不勾选“总是保持以上选择,不再询问”,那么每次用户触发都会弹出提示框。 3) 如果用户勾选“总是保持以上选择,不再询问”,那么将再也不会唤起这个对话框。同时,如果选择“取消”,那么以后每次调用这个api的时候,都会自动拒绝;如果选择“允许”,那么以后每次调用此api,都会自动允许授权。 目前小程序没有提供获取用户是否授权订阅消息的方法。通过wx.openSetting 方法无法获取用户是否授权消息订阅的信息,scope 列表没有订阅消息的内容。 如果想从自动拒绝转换到自动自动运行,需要打开小程序的设置去配置。设置方法:点击小程序右上角的三个点,打开如下对话框 [图片] 然后选择“设置”,在设置项里选择“订阅消息” [图片] [图片] 4)对于同一种消息,用户可以订阅多次,订阅多少次,就会收到多少次订阅消息,这个订阅次数是否有上限,官方没有说明,初步判断是不限的。但是,微信不会提供订阅的次数,因此需要在小程序的后端服务里存储用户订阅的次数。因此,我在微慕小程序专业版里,提供了一个给用户多次订阅的设置,并记录用户订阅的次数。 [图片] 如果用户需要某个消息服务,可以订阅多次,当然也可以在点击“订阅”的对话框里选择“取消”,“取消”一次也就减少一次订阅。 5)对于支付的场景,也需要用户确认是否订阅,这个我觉得不合理,支付后给用户一个订单推送消息应该是刚性需求,不需要再询问一遍用户是否订阅。 2.调用接口下发订阅消息 订阅消息下发的接口是小程序后台服务端调用:subscribeMessage.send,此方法类似下发模板消息的方法,详细调用说明见参考官方的链接: https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html 订阅消息的下发接口方法和模板消息稍有不同, 模板消息的json格式如下 [代码]"data": {[代码] [代码]"keyword1": {[代码] [代码]"value": "内容1",[代码] [代码]"color": "#000"[代码] [代码]},[代码] [代码]"keyword2": {[代码] [代码]"value": "内容2",[代码] [代码]"color": "#000"[代码] [代码]}[代码] [代码]}[代码] 而订阅消息的json格式如下: [代码]"data": {[代码] [代码]"thing1": {[代码] [代码]"value": "内容"[代码] [代码]},[代码] [代码]"number2": {[代码] [代码]"value": 20[代码] [代码]}[代码] 订阅消息的字段key是和数据类型有关,value的参数需要严格按照设置的类型提交,如果不按类型提交,会导致发送失败。同时如果是文本型的内容,字数也有限制,超过限制也会发送失败,但具体字数是多少,官方没有给出,同时中英文混合计算的长度也有差异,据我目前测试25个中文字符是可以的。希望官方能给出具体的字符长度限制的明确数字。 如果调用下发的次数大于用户的订阅次数,调用接口下发订阅消息会返回失败。报如下错误 [图片] 二.订阅消息使用心得1.订阅消息虽然把订阅的授权的交给了用户,但是也增加了用户使用难度,同时,一次性订阅只能收到一次,操作起来比较繁琐,如果不是刚需用户可能会首次就拒绝了这个服务,要想重新获取授权,需要用户自己打开小程序设置里去配置,颇为麻烦,小程序没有提供更简便的方法去唤起。 2.小程序的服务商为了获得更多给用户发送订阅消息的次数,肯定会想方设法去埋点引诱用户去点击订阅,这种诱导估计也是违规。 3.用户使用门槛和学习比较高,比如某个预约的服务,原来的场景是用户只要有提交表单,小程序就可以推送消息给用户,但是现在需要用户主动去订阅,无形中多了一步,如果用户不熟悉订阅消息或者直接点了“取消”,小程序就没法通知到用户了,用户可能因此错失服务,对商家和用户都是损失。 4.微信小程序将采用订阅消息,并逐步取消模板消息,虽然微信官方试图在方便用户和不打扰用户这两种选择里去寻求平衡,但订阅消息目前的模式恐怕无法达到这个期望,至少在我看来,无论对小程序的服务商,还是小程序的用户,都感到不方便。 update:2020年5月18日,日前订阅消息已经支持微信小程序开发工具。
2020-05-18 - 【笔记】小程序内部引导关注公众号的几种方式
今天早上起床看到群里有问到这个问题,才想起总结下这个需求 小程序内部引导关注公众号的4种方式 由于小程序某些功能存在诸多的限制,而公众号相对开放一些,所以一定会有把小程序用户引导关注公众号的需求,现记录如下 1、小程序关注组件,这个是官方已具有的,本文不做叙述,后面碰到示例截图补充 [图片] 该方式是有限制的,请具体了解官方文档 https://developers.weixin.qq.com/miniprogram/dev/component/official-account.html 公众号关注组件。当用户扫小程序码打开小程序时,开发者可在小程序内配置公众号关注组件,方便用户快捷关注公众号,可嵌套在原生组件内。 2、小程序内部嵌入公众号二维码图片,提示保存二维码图片到本地然后扫码关注,截图示例如下 3、通过文字描述,提示用户搜索公众号名字进而关注 [图片] 4、客服消息,这是本次笔记的重点 现通过小程序抽奖助手截图示例,下面截图仅仅代表方式3,客服消息方式 [图片] 占位 [图片] 占位 [图片] 占位 [图片] 占位 之前有朋友,通过app唤起小程序,然后再拉起客服消息发送公众号二维码,这种行为存在风险,建议慎用 ! [图片] 在APP报名课程后 拉起小程序,通过发送客服消息来引导关注公众号 之前:已明确提示用户是要关注公众号,不存在故意诱导行为。报名课程后让用户关注公众号,是为了提醒用户及时上课、提交作业等。 [图片]
2020-03-04 - 第三方平台为快速创建小程序设置小程序名称问题?
在第三创建小程序后,设置小程序名称返回错误信息:{"errcode":91015,"errmsg":"diff master"} 即:原始名不同类型主体不一致? 【请求地址】: https://api.weixin.qq.com/wxa/setnickname?access_token=28_bp1zbmpJiojkhXpldcq7xuCx1amjqeeU3e5JE1ieUMWKCT3C7D5lX1ZDh30IyqDcZxAb2WBIeZXuI6d4wd1T_VuWToIjU0-1fj4B270hv91b7MXSAMCB_U6jF3_E5gQNkmj0QsX08mOO9Qz3CZYjADDRON 【请求参数】:{"nick_name":"南洋大师傅","id_card":"m44NkZYmbDskPmFGU7ZbXO7B3B76ZUFWpwutoRIRzCoC_f0JMAKwdtEdk7fWB8T39eyoLPe8t-DDm6igmJSfSo1V2rtw6-SRJnKuOEMkX2w","license":"m44NkZYmbDskPmFGU7ZbXIJop3-k7DkT65W2cnq7BNSoeq-X8H06T0FqfYPQLpRiKcdhyKHTLRkwSe0FSNQV8UgLOBzR7etli-8ugbZRjFk"} 【错误信息】:{"errcode":91015,"errmsg":"diff master"} APPID:wx45b11da44bdd44ba
2020-01-02 - {"errcode":48001,"errmsg":"api unauthorized hints:
[图片] 问题是我们作为第三方平台,有一个商户的公众号,一直调用上面几个接口报错: {"errcode":48001,"errmsg":"api unauthorized hints: [jgOFjH0gE-2HIFVa!]"} (其中这个商户的小程序调用上面接口是正常的,只有公众号调用有问题) [图片] 其他商户的公众号和小程序调用这4个接口都正常, 然后网上查询了下类似问题,都没解决 公众号是已认证的 [图片] 公众号的授权也有 [图片] 公众号api权限也有(就只有3个是未获得,其他都是已以获得) [图片] 第三方平台的权限集都有(从报错内容来看,理论上就是下面这个权限没开通,但是已经开通了,只要在公众号授权了第三方平台,就ok了才对) [图片] 实在没辙了,客户等着解决问题呢,麻烦你们尽快联系我,微信号593022731
2019-12-30 - 第三方平台申请的小程序如何进入官方后台
来一间的上期、上上期开放社区文章推出了几个小程序实用技巧。但这些实用技巧有的是基于小程序官方后台。而很多小程序都是在小程序服务商的第三方平台申请的,这怎么破?怎么才能进入自己的小程序官方后台? 不废话!马上给你解答。 1、首先进入大家熟悉的微信公众号平台登录页。 [图片] 2、进入“找回账号或密码”页面。 [图片] 3、进入阅读通知,点击同意。 [图片] 4、进入填写待找回的账号页面。 [图片] 选择小程序,然后输入待找回小程序的名称点旁边放大镜进行搜索。最后勾选你要找回的小程序点下一步。 5、进入填写资料并验证身份证页面。 [图片] 这个页面要注意的是邮箱要用没有在微信注册过小程序、公众号、绑定过微信的邮箱。 最后再总结一下,找回官方小程序后台除了来一间上篇、上上篇那些。其实还可以注销小程序、提交附近小程序、小程序更全面的统计数据、订阅消息开通、小程序评测、开通流量主、开通广告主、搜索配置等等。看到这里的你,是不是没有这个需求也值得去小程序后台看看的冲动?小程序的更新速度还是耿耿的!
2019-11-27