背景:
如上图,我的小程序涉及图片功能上线还没两天就被人搞了(上传了黄图然后被举报)。通过查看得知UGC平台类小程序,涉及到平台内用户发布,平台都要对用户发布内容设置违法违规内容过滤机制。当天连夜修改于是有了这篇文章。
本文用到的图片内容安全检测为小程序自带的同步API:security.imgSecCheck
优点:免费(白嫖的),小程序自带,无须额外申请,格式支持PNG、JPEG、JPG、GIF,单个 appId 调用上限为 2000 次/分钟,200,000 次/天,基本满足需要。
缺点:图片大小限制1M ,图片尺寸不超过 750px x 1334px,还有就是这个API不太稳定的样子,超时的概率挺多,社区他们技术专员给的答案是__服务高峰时有少量超时导致__。
虽然文档写的是图片尺寸不超过 750px x 1334px,但是实际用的时候大过了也基本不报错。
代码实现:
小程序端:
timer = null
state = {
quality: 0.3,
cWidth: 0,
cHeight: 0,
}
//上传图片
chooseImage = () => {
const _ = this;
const { quality } = this.state
Taro.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.state
const _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.fileID
const res = await cloud.downloadFile({
fileID: fileID,
})
//这里也可以把fileID和用户关联起来add在记录里,方便观察。
const buffer = res.fileContent
return await cloud.openapi.security.imgSecCheck({
media: {
contentType: "image/png",
value: buffer
}
})
} catch (err) {
return err
}
}
测了几波下来基本不报错,检测也正常。
啥,你问我为啥不用微信的wx.compressImage
压缩图片接口api,因为它会反向压缩,压缩了还更大,社区里也有狠多反馈的问题。
以下是quality
设置为0.3时几次压缩大小测试,可以看到压缩还可以。图片大时可以动态检测原始图片大小设置quality
值。
最后欢迎关注
欢迎关注小程序“进阶的大前端
”,用云开发写的,1000多道前端面试题在线查看。