這次分享下“發帖功能”,這個功能其實風險蠻大的,特別是對一些敏感言論的控制,如果沒有做好可能導致小程式被封,所以除了必要的人工稽核和巡查以外,我們需要一些微信安全監測API的幫忙,在AI加持下,現在很多大公司對內容和圖片的效率大大提高了。
這個DEMO僅是一個流程示例,由於涉及到雲函式和“真”敏感圖,這裡就有文字圖代替。
發帖的功能只要理清思路,其實並不複雜,利用機器AI做內容審查是關鍵,直接關係到小程式的整體安全。
使用者選擇手機相簿或拍照
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。
內容檢查(重點)
由於內容安全對於小程式運營至關重要,稍有不慎就容易導致小程式被封,所以在這塊的校驗除了常規人工檢查外,我們還可以用到微信的內容安全API。
為什麼用微信官方提供的API? 主要有二點:有一定的免費額度,基於企鵝大廠的專業AI檢查。
1、雲函式+雲呼叫
目錄結構
├─checkContent
│ config.json //雲呼叫的許可權配置
│ index.js //雲伺服器node 入口檔案
│ package-lock.json
│ package.json // NPM包依賴
│ ...
複製程式碼
為什麼要強調這個? 因為本人一開始在用雲函式+雲呼叫的時候,經常會出現各種不明BUG,很多都是因為目錄裡面少傳檔案,或者少配置。
雲函式內容:
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個點
- 圖片security.imgSecCheck 方法只能接收buffer,所以需要把temp的臨時圖片轉化為buffer的形式傳過去,我們這裡用到 getFileSystemManager 的方法。
- 如果目錄檔案中沒有config.json,需要自己建一個,並且做一個授權的配置。
{
"permissions": {
"openapi": [
"security.msgSecCheck",
"security.imgSecCheck"
]
}
}
複製程式碼
2、檢查文字內容安全
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"
}
複製程式碼
應用場景舉例:
- 使用者個人資料違規文字檢測;
- 媒體新聞類使用者發表文章,評論內容檢測;
- 遊戲類使用者編輯上傳的素材(如答題類小遊戲使用者上傳的問題及答案)檢測等。 頻率限制:單個 appId 呼叫上限為 4000 次/分鐘,2,000,000 次/天*
通過wx.cloud.callFunction的方法呼叫checkContent的雲函式,檢查一段文字是否含有違法違規內容。
3、檢查圖片內容安全
//獲取 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)
}
})
}
})
複製程式碼
往期回顧:
[打怪升級]小程式評論回覆和發貼功能實戰(一)
[填坑手冊]小程式Canvas生成海報(一)
[拆彈時刻]小程式Canvas生成海報(二)
[填坑手冊]小程式目錄結構和component元件使用心得