微信小程序接入微信反垃圾接口

2,743 阅读3分钟

由于种种原因,小程序需要接入微信内容安全检查 Api。最终实现方案有点曲折,还没想到有什么更好的办法。

通过云函数调用 security.imgSecChecksecurity.msgSecCheck 实现图片和文字违法违规内容检查

实现思路

实现思路:在云函数中调用 微信内容安全检查 Api,图片上传前调用云函数来进行安全检查。

微信内容安全检查 Api 有三个接口:security.imgSecChecksecurity.mediaCheckAsyncsecurity.msgSecCheck

  • security.mediaCheckAsync:可异步校验图片/音频是否含有违法违规内容,需要传入音频或图片url,单个文件大小不超过 10M只支持在服务端调用

  • security.imgSecChecksecurity.msgSecCheck:两个接口分别校验图片和文字,图片大小限制为 1M。支持服务端调用和云函数调用。

在开发的小程序场景中,需要检查文字,图片需要在上传前进行校验,并且在服务端改动会比较麻烦。于是选择使用在云函数中调用security.imgSecChecksecurity.msgSecCheck

具体实现

一、云函数实现


cloud = require('wx-server-sdk');
cloud.init();

exports.main = async function (event, context) {
  let opts = {}
  let fun = '';
  if (event.type === 2) { // 文字检查
    opts = {
      content: event.content || ''
    };
    fun = cloud.openapi.security.msgSecCheck(opts);
  } else {// 图片检查 
    let imgbase64 = event.imgbase64;
    let buffer = Buffer.from(imgbase64, 'base64');
    opts = {
      media: {
        contentType: 'image/jpg',
        value: buffer
      }
    };
    fun = cloud.openapi.security.imgSecCheck(opts);
  }
  
  return fun.then(res => { 
    return res;
  }).catch(err => { 
    return err;
  });
}

二、小程序代码

//文字信息安全检查
const msgSecCheck = function (content) { 
  return new Promise((resolve, reject) => { 
    wx.cloud.callFunction({
      name: 'securityCheck',
      data: { content: content, type: 2 },
    }).then(res => {
      if (res && res.result && res.result.errCode === 87014) {
        resolve(true);
      } else {
        resolve(false);
      }
    }).catch(err => {
      //只要检查失败,都算作没有安全风险
      resolve(false);
    })
  })
  
}
// 图片安全检查
// tempFiles:{path:'',size:''}
const checkImgSafe = function (tempFiles) {

    return new Promise((resolve, reject) => {
        // 压缩图片
        getImg(tempFiles.path).then(tmpPath => {
            //先将图片转换为base64,然后调用云函数
            const fs = wx.getFileSystemManager();
            fs.readFile({
                filePath: tmpPath,
                encoding: 'base64',
                success: function (res) {
                    wx.cloud.callFunction({
                        name: 'securityCheck',
                        data: { imgbase64: res.data },
                    }).then(res => {
                        if (res && res.result && res.result.errCode === 87014) {
                            reject(); //有安全风险
                        } else {
                            resolve();
                        }
                    }).catch(err => {
                        //只要检查失败,都算作没有安全风险
                        resolve();
                    })
                }
            });
        }).catch(err => {
            resolve();
        });
        
    });
};

// 图片压缩
const getImg = function (path) {
    return new Promise((resolve, reject) => {
        wx.getImageInfo({
            src: path,
            success(res) {
                // 图片原尺寸
                let height = res.height;
                let width = res.width;

                let maxWidth = 200;
                let maxHeight = 200;

                // 压缩后尺寸
                let targetWidth = width;
                let targetHeight = height;
                // 等比例压缩,如果宽度大于高度,则宽度优先,否则高度优先
                if (width > maxWidth || height > maxHeight) {
                    if (width / height > maxWidth / maxHeight) {
                        // 要求宽度*(原生图片比例)=新图片尺寸
                        targetWidth = maxWidth;
                        targetHeight = Math.round(maxWidth * (height / width));
                    } else {
                        targetHeight = maxHeight;
                        targetWidth = Math.round(maxHeight * (width / height));
                    }
                }

                const ctx = wx.createCanvasContext("canvas-img");

                ctx.clearRect(0, 0, targetWidth, targetHeight);
                ctx.drawImage(path, 0, 0, targetWidth, targetHeight);
                ctx.draw(true, function () {
                    wx.canvasToTempFilePath({
                        canvasId: "canvas-img",
                        x: 0,
                        y: 0,
                        width: targetWidth,
                        height: targetHeight,
                        quality: 0.5,
                        fileType: 'jpg',
                        success: function (res) {
                            resolve(res.tempFilePath)
                        },
                        fail: function (err) {
                            reject(err)
                        }
                    });
                });
            },
            fail: function (err) {
                reject(err);
            }
        })

    })
};
<!-- wxml -->
<canvas canvas-id="canvas-img" style="top:-500;position:fixed;"></canvas>

注意事项:

  • 图片需要先压缩:两个原因:openapi.security.imgSecCheck可检查图片大小宣称 1M 以下,实测提示信息里写的不能超过 5120kb;图片还没有上传就需要检查,只有本地路径,因此无法传 url,此处将图片转为 base64 格式。实测调用云函数时,传输 base64 200kb+ 的参数就会失败( IDE 没有问题,客户端会报错 cloud.callFunction:fail timeout for result fetching )。
  • canvas不能display:none。这里将 canvas 元素放到页面外看不到的区域。

tips:代码写的比较挫,不知道是否有更好的办法。