背景:
如上图,我的小程序涉及图片功能上线还没两天就被人搞了(上传了黄图然后被举报)。通过查看得知UGC平台类小程序,涉及到平台内用户发布,平台都要对用户发布内容设置违法违规内容过滤机制。当天连夜修改于是有了这篇文章。
本文用到的图片内容安全检测为小程序自带的同步API:security.imgSecCheck
优点:免费(白嫖的),小程序自带,无须额外申请,格式支持PNG、JPEG、JPG、GIF,单个 appId 调用上限为 2000 次/分钟,200,000 次/天,基本满足需要。
缺点:图片大小限制1M ,图片尺寸不超过 750px x 1334px,还有就是这个API不太稳定的样子,超时的概率挺多,社区他们技术专员给的答案是服务高峰时有少量超时导致。
虽然文档写的是图片尺寸不超过 750px x 1334px,但是实际用的时候大过了也基本不报错。
代码实现:
小程序端:
timer = nullstate = {quality: 0.3,cWidth: 0,cHeight: 0,}//上传图片chooseImage = () => {const _ = this;const { quality } = this.stateTaro.chooseImage({count: 1,sizeType: ['original', 'compressed'],sourceType: ['album'],success(result) {const tempFilePath = result.tempFilePaths[0];let size = result.tempFiles[0].size;if (size > 1024 * 1024 * 8) {//大于8M返回return Taro.showToast({title: '图片大于8M啦',icon: 'none'})}if (size < 1024 * 800) { //小于800kb压缩const status = await _.imgSecCheck(tempFilePath)if (status == true) {console.log('通过了处理');//走检测通过处理}} else {Taro.getImageInfo({src: tempFilePath,success: function (res) {_.setState({//设置原始宽高cWidth: res.width,cHeight: res.height}, async () => {try {const imagePath = await _.getCanvasImg(tempFilePath, res.width, res.height, quality);const status = await _.imgSecCheck(imagePath)if (status == true) {console.log('通过了处理');//走检测通过处理}} catch (error) {}})}})}}})}//压缩图片getCanvasImg(path, w, h, q) {return new Promise((resolve, reject) => {var _ = this;const ctx = Taro.createCanvasContext('myCanvas');ctx.clearRect(0, 0, w, h);ctx.drawImage(path, 0, 0, w, h);ctx.draw(false, function () {_.timer = setTimeout(() => {Taro.canvasToTempFilePath({canvasId: 'myCanvas',fileType: 'jpg',quality: q,destWidth: w,destHeight: h,success: function success(res) {_.setState({imagePath:res.tempFilePath})clearTimeout(_.timer)resolve(res.tempFilePath)},fail: function (e) {clearTimeout(_.timer)Taro.showModal({title: '提示',content: JSON.stringify(e),})reject(e)}});}, 500)});})}//检测图片async imgSecCheck(src) {try {//上传到云存储const uploadResult = await Taro.cloud.uploadFile({//云储存的路径及文件名cloudPath: new Date().getTime() + "-" + Math.floor(Math.random() * 1000),filePath: src,})//图片检测const json = await Taro.cloud.callFunction({name: "service",data: {action: "checkImg",fileID: uploadResult.fileID}})if (json.result.errCode == 0) { //图片没问题return true;}else if (json.result.errCode == 87014) {return Taro.showToast({title: '图片含有违法违规内容',duration: 2000,icon: 'none'});}else {return Taro.showToast({title: '请重新上传',duration: 2000,icon: 'none'});}} catch (error) {return Taro.showToast({title: error,duration: 2000,icon: 'none'});}}
render() {const { cWidth, cHeight} = this.stateconst _style = {width: cWidth + 'px',height: cHeight + 'px',position: 'fixed',top: '-9999px',left: '-9999px'}return (<View><Button onClick={this.chooseImage}>上传</Button><Canvas canvas-id='myCanvas' className='myCanvas' style={_style}></Canvas></View>)}
云函数端:
module.exports = async (event, context) => {try {const fileID = event.fileIDconst res = await cloud.downloadFile({fileID: fileID,})//这里也可以把fileID和用户关联起来add在记录里,方便观察。const buffer = res.fileContentreturn await cloud.openapi.security.imgSecCheck({media: {contentType: "image/png",value: buffer}})} catch (err) {return err}}
测了几波下来基本不报错,检测也正常。
啥,你问我为啥不用微信的pressImage
压缩图片接口api,因为它会反向压缩,压缩了还更大,社区里也有狠多反馈的问题。
以下是quality
设置为0.3时几次压缩大小测试,可以看到压缩还可以。图片大时可以动态检测原始图片大小设置quality
值。
最后欢迎关注
欢迎关注小程序“进阶的大前端
”,用云开发写的,1000多道前端面试题在线查看。
如果觉得《小程序图片安全审核方案与security.imgSecCheck不能校验超过1M图片的解决思路》对你有帮助,请点赞、收藏,并留下你的观点哦!