此次分享下“发帖功能”,这个功能其实风险蛮大的,特别是对一些敏感言论的控制,若是没有作好可能致使小程序被封,因此除了必要的人工审核和巡查之外,咱们须要一些微信安全监测API的帮忙,在AI加持下,如今不少大公司对内容和图片的效率大大提升了。html
这个DEMO仅是一个流程示例,因为涉及到云函数和“真”敏感图,这里就有文字图代替。node
发帖的功能只要理清思路,其实并不复杂,利用机器AI作内容审查是关键,直接关系到小程序的总体安全。json
[toc]小程序
let tempImg = 0; //表明已选择的图片 wx.chooseImage({ count: 3 - tempImg.length, //选择不超过3张照片,去掉当前已经选择的照片 sizeType: ['original', 'compressed'], //获取原图或者压缩图 sourceType: ['album', 'camera'], //获取图片来源 图库、拍照 success(res) { // tempFilePath能够做为img标签的src属性显示图片 let tempFilePaths = res.tempFilePaths; console.log(tempFilePaths); //举例:这里能够size 来判断图片是否大于 1MB,方便后面内容检查 if (res.tempFiles[0] && res.tempFiles[0].size > 1024 * 1024) { console.log("图片大于1MB啦") } } })
这里用到的方法是chooseImage,它能够设置让用户选择手机图片库和拍照得到,须要注意的是考虑到后面要用微信自带API作图片安全检查,图片大小不能超过1MB,因此须要设置sizeType为compressed。segmentfault
因为内容安全对于小程序运营相当重要,稍有不慎就容易致使小程序被封,因此在这块的校验除了常规人工检查外,咱们还能够用到微信的内容安全API。api
为何用微信官方提供的API?
主要有二点:有必定的免费额度,基于企鹅大厂的专业AI检查。安全
目录结构服务器
├─checkContent │ config.json //云调用的权限配置 │ index.js //云服务器node 入口文件 │ package-lock.json │ package.json // NPM包依赖 │ ...
为何要强调这个?
由于本人一开始在用云函数+云调用的时候,常常会出现各类不明BUG,不少都是由于目录里面少传文件,或者少配置。微信
云函数内容:app
const cloud = require('wx-server-sdk'); cloud.init(); exports.main = async (event, context) => { console.log(event.txt); const { value, txt } = event; try { let msgR = false; let imageR = false; //检查 文字内容是否违规 if (txt) { msgR = await cloud.openapi.security.msgSecCheck({ content: txt }) } //检查 图片内容是否违规 if (value) { imageR = await cloud.openapi.security.imgSecCheck({ media: { header: { 'Content-Type': 'application/octet-stream' }, contentType: 'image/png', value: Buffer.from(value) } }) } return { msgR, //内容检查返回值 imageR //图片检查返回值 }; } catch (err) { // 错误处理 // err.errCode !== 0 return err } }
这里主要用到security.msgSecCheck和security.imgSecCheck这2个微信开放云调用方法(需开发者工具版本 >= 1.02.1904090),以往咱们还要在服务器上单独写个方法,如今变得十分的方便,直接在云函数中调用便可。
这里须要重点说2个点
{ "permissions": { "openapi": [ "security.msgSecCheck", "security.imgSecCheck" ] } }
wx.cloud.callFunction({ name: 'checkContent', data: { txt: "乐于分享,一块儿进步" }, success(_res) { console.log(_res) }, fail(_res) { console.log(_res) } }) //返回值参考 { "errMsg": "cloud.callFunction:ok", "result": { "msgR": { "errMsg": "openapi.security.msgSecCheck:ok", "errCode": 0 }, "imageR": false }, "requestID": "77952319-b2b4-11e9-bdc8-525400192d0e" }
应用场景举例:
经过wx.cloud.callFunction的方法调用checkContent的云函数,检查一段文本是否含有违法违规内容。
//获取 temp临时图片文件的 buffer wx.getFileSystemManager().readFile({ filePath: tempImg[0], //这里作示例,因此就选取第一张图片 success: buffer => { console.log(buffer.data) //这里是 云函数调用方法 wx.cloud.callFunction({ name: 'checkContent', data: { value: buffer.data }, success(json) { console.log(json.result.imageR) if (json.result.imageR.errCode == 87014) { wx.showToast({ title: '图片含有违法违规内容', icon: 'none' }); console.log("bad") } else { //图片正常 } } }) } }) //返回值参考 { "errMsg": "cloud.callFunction:ok", "result": { "msgR": false, "imageR": { "errMsg": "openapi.security.imgSecCheck:ok", "errCode": 0 } }, "requestID": "c126353c2d-b40b-11e9-81c4d-525400235f2a" }
应用场景举例:
图片智能鉴黄:涉及拍照的工具类应用(如美拍,识图类应用)用户拍照上传检测;电商类商品上架图片检测;媒体类用户文章里的图片检测等;
敏感人脸识别:用户头像;媒体类用户文章里的图片检测;社交类用户上传的图片检测等。 频率限制:单个 appId 调用上限为 2000 次/分钟,200,000 次/天*(图片大小限制:1M)
这里先要用 getFileSystemManager() 获取临时图片的buffer(这个是重点),而后再经过wx.cloud.callFunction的方法调用 checkContent的云函数中security.imgSecCheck的方法,校验一张图片是否含有违法违规内容。
一开始本人调试的时候,也遇到没法上传的问题,必须经过文件管理(getFileSystemManager)获取buffer后才能上传检查图片,耗费了本人很多debugger时间。
本来想作个实际的demo(代码片断)分享给你们打开参考的,可是云函数必须是一个已注册的APPID,无奈只能贴代码。
这里主要仍是提供一个总体思路,但愿能帮助你们减小开发成本,更好的解决问题和完成任务 ^_^
html部分:
<!-- pages/post /index.wxml --> <view class="wrap"> <view class="title"> <input placeholder="智酷方程式,乐于分享" maxlength="30" bindinput="getTitle"/> </view> <view class="content"> <textarea auto-focus="true" maxlength="200" bindinput="textareaCtrl" placeholder-style="color:#999;" placeholder="关注公众号,一块儿学习,一块儿进步" /> <view class='fontNum'>{{content.length}}/200</view> </view> <view class="chooseImg"> <block wx:for="{{tempImg}}" wx:for-item="item" wx:key="ids" wx:for-index="index"> <view class="chooseImgBox"> <image src="{{item}}" /> <view data-index="{{index}}" catch:tap="removeImg" class="removeImg"></view> </view> </block> <!-- 判断图片 大于等于3张的时候 取消 更多 --> <block wx:if="{{tempImg.length < 3}}"> <view class="chooseImgBoxMore" catch:tap="choosePhoto"> <view class="arrow"></view> </view> </block> </view> <view class='submit' catch:tap="submitPost"> <view class='blue'>提交</view> <view>取消</view> </view> </view>
JS部分:
Page({ /** * 页面的初始数据 */ data: { titleDetail: "", //帖子title内容 content: "", //发帖内容 tempImg: [], //选择图片的缩略图,临时地址 }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { wx.cloud.init(); }, /** * 生命周期函数--监听页面显示 */ onShow: function () { }, /** * 检测输入字数 * @param {object} e */ textareaCtrl: function (e) { if (e.detail.value) { this.setData({ content: e.detail.value }) } else { this.setData({ content: "" }) } }, /** * 选择图片 */ choosePhoto() { let self = this; let tempImg = self.data.tempImg; if (tempImg.length > 2) { return; } wx.chooseImage({ count: 3 - tempImg.length, //选择不超过3张照片,去掉当前已经选择的照片 sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success(res) { console.log(res); // tempFilePath能够做为img标签的src属性显示图片 let tempFilePaths = res.tempFilePaths; tempImg = tempImg.concat(tempFilePaths); console.log(tempImg); self.setData({ tempImg }) wx.getFileSystemManager().readFile({ filePath: tempImg[0], success: buffer => { console.log(buffer.data) wx.cloud.callFunction({ name: 'checkContent', data: { value: buffer.data }, success(json) { console.log(JSON.stringify(json)) console.log(json.result.imageR) if (json.result.imageR.errCode == 87014) { wx.showToast({ title: '图片含有违法违规内容', icon: 'none' }); console.log("bad") } else { //图片正常 } } }) } }) }, fail: err => { console.log(err) } }) }, /** * 删除照片 */ removeImg(e) { let self = this; let index = e.currentTarget.dataset.index; console.log(e); let tempImg = self.data.tempImg; tempImg.splice(index, 1); self.setData({ tempImg }) }, /** * 发贴 */ submitPost(e) { let { titleDetail, content } = this.data; wx.cloud.callFunction({ name: 'checkContent', data: { txt: content }, success(_res) { console.log(JSON.stringify(_res)) wx.navigateTo({ url: "/pages/postimg/result" }) }, fail(_res) { console.log(_res) } }) } })
往期回顾:
[[[打怪升级]小程序评论回复和发贴功能实战(一)](https://segmentfault.com/a/11...
[[填坑手册]小程序Canvas生成海报(一)](https://segmentfault.com/a/11...
[[拆弹时刻]小程序Canvas生成海报(二)](https://segmentfault.com/a/11...
[[填坑手册]小程序目录结构和component组件使用心得](https://segmentfault.com/a/11...