天天看點

做好内容安全檢測,和風險說「再見」!(上)

再也不用一字一句地人工過濾敏感詞了!

前言

内容安全檢測,是每一個小程式主都面臨的“頭疼”問題,輕則短暫性不可通路,重則永久封号,甚至關小黑屋。本文将為您詳細說明,如何在小程式中對一段文本進行合法内容檢測,以判斷是否含有違法違規内容。

本文重點為你講述:

  • 内容安全檢測常見應用場景及解決辦法
  • 學會使用小程式·雲開發的雲函數+結合request-promise第三方庫實作内容請求校驗
  • 掌握如何在小程式端請求雲函數(有别于傳統的wx.request的方式(類似AJax))
  • 在雲開發的雲函數端,利用第三方https請求庫(request,request-promise),擷取Access_token,以及向微信官方提供的内容檢測接口發請求進行校驗
  • 雲函數端與小程式端錯誤碼的處理

01.背景

無論是小程式還是自行開發的一些類似社交,帶有使用者自行産生内容的軟體應用,例如:即時通訊,社群,論壇,音視訊直播等,對于接入内容安全的檢測是非常有必要的。

對于小程式而言,這一點在稽核上是非常嚴格的,淨化言行,做一個知法守法的人很重要...

接入内容安全檢測,規避輸入一些違法違規低俗等内容,避免辛辛苦苦開發出來的應用。

被惡意上傳反動言論或上傳一些違規内容(文字/圖檔/視訊等),導緻小程式或應用被下架,或遭永久禁封,或個人及公司被公安機關打電話,約喝茶等,這樣的話,就得不償失了的。

02.應用場景

  • 檢測小程式使用者個人文字資料是否違規
  • 針對特點詞彙(如過于商業以及營銷之類的詞)可以進行過濾或禁止輸入
  • 在内容釋出之前自動檢測使用者發表的資訊(包括評論、留言等)是否違規

03.解決辦法

圍繞如何處理内容安全檢測問題,一般有3種方法:

方案1****:引入第三方接口對内容進行校驗(例如:百度AI内容稽核平台,網易雲盾等)

方案2: 公司背景小夥伴自行開發文本,圖檔,音視訊等内容稽核接口

方案3: 小程式服務端提供的API進行校驗

每一種方法各有優劣勢,具體如下圖。

解決方案 優勢 劣勢
1 引入第三方接口對内容進行校驗 前端同學隻需按照官方提供的第三方接口文檔,進行校驗即可,無需背景介入,功能強大,覆寫範圍廣 接口調用的頻次有限制,收費
2 公司背景小夥伴自行開發文本,圖檔,音視訊等内容稽核接口 背景小夥伴自己造輪子,根據自己的業務需求以及使用者屬性,自定義内容稽核機制 開發周期長,成本大,難以覆寫全面
3 調用小程式服務端提供的内容安全API進行校驗 簡單,高效 想不出來,因為相比前兩種方案,對于不依賴後端接口的開發者來說,簡直是雪中送炭

在微信小程式生态下,官方提供了2種路徑幫助使用者解決内容檢測問題,即

  • 使用伺服器開發模式,通過HTTPS調用
  • 使用小程式·雲開發,通過雲函數或雲調用來實作。

伺服器開發模式,相信大家都相對比較熟悉,在此就不再贅述。接下來為大家重點介紹,如何通過小程式·雲開發的雲函數實作内容安全檢測。

04.通過雲開發的雲函數+request-promise第三方庫實作内容請求校驗

Step 1: 在小程式端先布局:完成靜态頁面。(pages檔案夾下的檔案都是屬于小程式前端代碼,每個檔案夾目錄代表的就是一個子產品,一個頁面)

小程式前端wxml代碼示例

<view class="container">
  <textarea class="content" placeholder="寫點文字..." bindinput="onInput" auto-focus bindfocus="onFocus" bindblur="onBlur">
  </textarea>
</view>

<view class="footer">
  <button class="send-btn" size="default" bind:tap="send">釋出</button>
</view>
           

小程式前端wxss代碼示例

/* pages/msgSecCheck/msgSecCheck.wxss */
.container {
  padding: 20rpx;
}

.content {
  width: 100%;
  height: 360rpx;
  box-sizing: border-box;
  font-size: 32rpx;
  border: 1px solid #ccc;
}

.footer {
  width: 100%;
  height: 80rpx;
  line-height: 80rpx;
  position: fixed;
  bottom: 0;
  box-sizing: border-box;
  background: #34bfa3;
}

.send-btn {
  width: 100% !important;
  color: #fff;
  font-size: 32rpx;
}

button {
  width: 100%;
  background: #34bfa3;
  border-radius: 0rpx;
}

button::after {
  border-radius: 0rpx !important;
}
           

經過wxml與wxss的編寫後,UI最終長成這樣

Step 2: 完成小程式端業務邏輯的處理

小程式端邏輯JS代碼示例

// pages/msgSecCheck/msgSecCheck.js
Page({

  /**
   * 頁面的初始資料
   */
  data: {
    textareaVal: ''   // 頁面中需要顯示的資料,初始化定義在data下面
  },

  /**
   * 生命周期函數--監聽頁面加載
   */
  onLoad: function (options) {

  },
  // 監聽表單時,資料有變化時
  onInput(event) {
    let textVal = event.detail.value;
    this.setData({
      textareaVal: textVal
    })
    
  },

  // 聚焦焦點時
  onFocus() {
    console.log('聚焦焦點時');
  },

  // 失去焦點時
  onBlur(event) {
    console.log("失去焦點時");
    // 前端可進行手動的弱校驗,也可以在失去焦點時發送請求進行文本的校驗,但是每次失去焦點就請求一次,這樣是消耗雲資源的,在釋出時候與失去焦點做校驗兩者都可以


  },

  // 釋出
  send() {
    console.log("觸發釋出按鈕")
    wx.cloud.callFunction({ // 請求msgSecCheck1雲函數
      name: 'msgSecCheck1',
      data: {
        content: this.data.textareaVal // 需要向雲函數msgSecCheck1傳入的值
      }

    }).then(res => { // 成功時的響應傳回結果
      console.log(res);
    }).catch(err => { // 失敗時,傳回的結果
      console.error(err);
    })
    
  }

})
           

Step 3 :服務端邏輯處理。在小程式雲函數端建立雲函數msgSecCheck1,這個名字你可以自定義,與小程式前端請求的名字保持一緻就可以了。

選中雲函數,右鍵并打開指令行終端安裝request,request-promise,因為request-promise依賴于request,兩個都要安裝,最後一鍵上傳部署就可以了

npm install request
npm install request-promise
           

如果遇到在小程式端請求雲函數時,遇到類似下面的錯誤,找不到什麼xxx子產品之類的 先看錯誤碼,然後在官方文檔中找到該錯誤碼代表的含義

一看錯誤,沒有找到子產品,在雲函數的目錄下的package.json中檢視是否有安裝錯誤中提示的包的,要是沒有的話,就安裝一下就可以了的,同時記得每次更改後都要上傳部署一下,也可以選擇雲函數中檔案的增量上傳

接下來是将是本文的重點内容!

Step 4 :通過雲函數+****request-promise實作内容安全檢測

對于小程式開發,其實與web端開發也是類似,給元素綁定事件,然後擷取元素,隻是小程式端沒有DOM,BOM的那一套東西,它是資料驅動視圖的,吸收了Angular,Vue,React的各個架構的優點,形成了自己的一套規範。

如果有這方面開發經驗的小夥伴來說,平緩過度到小程式開發當中來,你會發現總會有驚人的相似,用的語言都是JavaScript,但是與web開發還是多少有很多差異的,這裡就不拓展了。

廢話不多說,直接上代碼 :

小程式前端邏輯代碼:

// 點選發送按鈕,對輸入的文本内容進行校驗
 send() {
    wx.cloud.callFunction({
      name: 'msgSecCheck1', // 雲函數的名稱
      data: { // 需要向雲函數傳遞過去的資料
        content: this.data.textareaVal // 具體要檢測的内容
      }
    }).then(res => { // 成功時,做什麼事情
      console.log(res);
      // 檢測到文本成功時,做一些業務

    }).catch(err => { // 失敗時,做什麼事情
      // 失敗時,也就是違規做一些使用者提示,或者禁止下一步操作等之類的業務邏輯操作

      console.error(err);
    })
  }
           

上面的代碼還可以在優化一下,就是将請求雲函數的代碼封裝成一個函數。

如下所示,不封裝也是沒事的,隻是我習慣性封裝一下,如果其他地方也用到該雲函數,那麼直接調用,避免寫重複的代碼。

下面是将請求雲函數的部分核心代碼:

// 釋出
  send() {
    // 請求msgSecCheck1雲函數,對文本内容進行校驗
    this._requestCloudMsgCheck();
  },

  _requestCloudMsgCheck() {
    let textareaVal = this.data.textareaVal;
    wx.cloud.callFunction({
      name: 'msgSecCheck1',
      data: {
        content: textareaVal // 這裡可以使用官方文檔測試用例,特3456書yuuo莞6543李zxcz蒜7782法fgnv級
      }
    }).then(res => {
      console.log(res);
      // 檢測到文本成功時,做一些業務
    }).catch(err => {
      // 失敗時,也就是違規做一些使用者提示,或者禁止下一步操作等之類的業務邏輯操作
      console.error(err);
    })
  }
           

至于是在失去焦點事件時發送請求還是在點選發送按鈕時發送請求,兩種方式都可以。

您也可以自定義文本校驗,而我個人覺得在小程式端,失去焦點時,可以自定義做一些正常敏感詞的弱校驗,而在點選發送按鈕時,做強校驗 。

如果是放在失去焦點時就立馬請求,這樣請求次數會增多,而放在點選發送按鈕時進行校驗,一定程度上可以減少小程式端頻繁請求。

接下來就是處理雲函數端,使用request-promise請求請求微信内容安全接口的示例代碼。

/*
 *  Description: 利用第三方庫request-promise請求微信内容安全接口
 *
 * 相關文檔連結:
 * 微信文本内容安全接口文檔https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/sec-check/security.msgSecCheck.html
 * access_token擷取調用憑證文檔
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html
 *
 * request-promise使用文檔: https://github.com/request/request-promise
 *
 */

const APPID = "wx21baa58c6180c2eb"; // 注意是你自己小程式的appid
const APPSECRET = ""; // 你自己小程式的appsecret
// 安全校驗接口
const msgCheckURL = `https://api.weixin.qq.com/wxa/msg_sec_check?access_token=`;
// 向下面的這個地止發送請求,攜帶appid和appsecret參數,擷取token認證
const tokenURL = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`
// 雲函數入口檔案
const cloud = require('wx-server-sdk')

cloud.init()

// 引入request-promise
const rp = require('request-promise');

// 雲函數入口函數
exports.main = async(event, context) => {
  try {
    let tokenResponse = await rp(tokenURL);
    // 擷取token值,因為傳回的結果是字元串,需要用JSON.parse轉化為json對象
    let getAccessToken = JSON.parse(tokenResponse).access_token;
    // 請求微信内容安全接口,post請求,傳回最終的校驗結果
    let checkResponse = await rp({
      method: 'POST',
      url: `${msgCheckURL}${getAccessToken}`,
      body: {
        content: event.content // 這裡的event.content是小程式端傳過來的值,content是要向内容接口校驗的内容
      },
      json: true
    })
    return checkResponse;
  } catch (err) {
      console.error(err);
  }
}
           

當你在小程式端輸入文本,發送請求時,檢視控制台下的結果時,功能是沒有問題的。

特3456書yuuo莞6543李zxcz蒜7782法fgnv級
完2347全dfji試3726測asad感3847知qwez到
           

您可以根據官方文檔中提供的測試用例,進行測試,看具體的傳回結果的。

(控制台錯誤碼)

(合規内容)

雲函數請求成功,看看錯誤資訊的回報,對于熟悉該錯誤碼的人清楚該文本違規了,但是回報不是很明顯,即使當下自己很清楚,然而,在過幾個月在回來看代碼,你或許都不知道是啥意思。

Step 5 :錯誤碼的正确處理方式

對于處理錯誤碼,傳回具體的合适資訊,對于調試代碼,排查問題,也是非常重要 。

這些錯誤碼具體的含義,在官方文檔裡都有對應的解釋,不用去記,去查文檔就行。

在面試中,有很多面試官喜歡問http相關狀态碼的問題,狀态碼有很多,也真的記不住,但是常見的錯誤http狀态碼還是要知道的,我覺得,具體知道怎麼處理,怎麼查文檔就可以了。

真正考驗背後目的是,對于根據後端傳回的狀态碼,判斷接口哪裡出了問題,定位是前端問題還是後端問題,這是一個非常常見的問題。

如果你說你不知道,沒有處理過,對于候選人,那肯定是沒有信服力的,無論是成功狀态還是失敗狀态,都是應該有對應的使用者提示。

05.完整文本安全校驗示例代碼

/*
 *
 * 相關文檔連結:
 * 微信文本内容安全接口文檔https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/sec-check/security.msgSecCheck.html
 * access_token擷取調用憑證文檔
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html
 *
 * request-promise使用文檔: https://github.com/request/request-promise
 *
 */

const APPID = "wx21baa58c6180c2eb";
const APPSECRET = "";

const msgCheckURL = `https://api.weixin.qq.com/wxa/msg_sec_check?access_token=`;
// 向下面的這個地止發送請求,攜帶appid和appsecret參數,擷取token認證
const tokenURL = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`
// 雲函數入口檔案
const cloud = require('wx-server-sdk')

cloud.init()

// 引入request-promise
const rp = require('request-promise');

// 雲函數入口函數
exports.main = async(event, context) => {
  try {
    let tokenResponse = await rp(tokenURL);
    // 擷取token值,因為傳回的結果是字元串,需要用JSON.parse轉化為json對象
    let getAccessToken = JSON.parse(tokenResponse).access_token;
    // 請求微信内容安全接口,post請求,傳回最終的校驗結果
    let checkResponse = await rp({
      method: 'POST',
      url: `${msgCheckURL}${getAccessToken}`,
      body: {
        content: event.content // 這裡的event.content是小程式端傳過來的值,content是要向内容接口校驗的内容
      },
      json: true
    })

    // 有必要根據錯誤碼,确定内容是否違規
    if (checkResponse.errcode == 87014) {
      return {
        code: 500,
        msg: "内容含有違法違規内容",
        data: checkResponse
      }
    } else {
      return {
        code: 200,
        msg: "内容OK",
        data: checkResponse
      }
    }
  } catch (err) {
    if (err.errcode == 87014) {
      return {
        code: 500,
        msg: '内容含有違法違規内容',
        data: err
      }
    } else {
      return {
        code: 502,
        msg: '調用msgCheckURL接口異常',
        data: err
      }
    }
  }
}
           

在雲函數端,經過添加錯誤碼的判斷之後,在來看看小程式端發送的請求,傳回的結果。

(這與沒有添加錯誤碼判斷,是不一樣的,有具體的錯誤資訊内容)

至此,我們在小程式端可以根據這個傳回的錯誤碼或成功碼,進行一些業務邏輯處理的,比如給一些使用者提示,在資料插入資料庫之前就做一些判斷操作,隻有内容合規時,才插入資料庫,進入下一步的業務邏輯處理。

_requestCloudMsgCheck() {
    let textareaVal = this.data.textareaVal;
    wx.cloud.callFunction({
      name: 'msgSecCheck1',
      data: {
        content: textareaVal
      }
    }).then(res => {
      console.log(res);
      const errcode = res.result.data.errcode;
      // 檢測到文本錯誤時,做一些業務
      if (87014 === errcode) {
         wx.showToast({ // 當内容違規時,做一些使用者提示
           title: '您輸入的文本内容含有敏感内容,請重新輸入',
         })
      }else {
         // 成功時做其他業務操作
      }
    }).catch(err => {
      // 失敗時,也就是違規做一些使用者提示,或者禁止下一步操作等之類的業務邏輯操作
      console.error(err);
    })
  }
           

(當輸入的内容有違規時,給一些使用者提示或者阻止下一步操作等的)

注意在雲函數(後)端處理錯誤碼與小程式端都是要進行處理的,兩者不要混淆了的,小程式端最終的一些業務邏輯判斷,是根據後端接口傳回的狀态,最終決定要做什麼操作的。

至此,通過request-promise庫就完成了文本内容校驗的問題。

這個request,request-promise庫非常實用,功能也非常強大,類似這種庫,常見什麼got,axios等之類的,都是支援promise風格的 處理方式大同小異,大家可以去npm或github上閱讀相關使用文檔的。

06.結語

在小程式中有多種解決方案,推薦使用小程式端請求雲開發雲函數的方式,無論是不使用雲函數方式,自己有後端服務,擷取access_token都應該是從後端傳回給前端的。

而小程式的秘鑰 AppSecret是不應該放在小程式端的,那樣不安全的,無論是伺服器開發模式還是小程式·雲開發模式,都繞不過背景請求微信提供的内容安全接口,然後在傳回給小程式端 。

其實在小程式·雲開發中,還提供了一種更簡便的方法,那就是雲調用,它是小程式·雲開發提供的在雲函數中調用微信開放接口的能力,隻需簡單的進行配置一下就可以了。

限于篇幅所緻,放在下一節介紹。

reference:方案1參考連結:

微信内容安全:

https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/sec-check/security.msgSecCheck.html

雲調用

https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/capabilities.html#%E4%BA%91%E5%87%BD%E6%95%B0

百度文本稽核

https://ai.baidu.com/tech/textcensoring

網易雲盾

https://dun.163.com/product/text-detection

公衆号:騰訊雲雲開發

騰訊雲雲開發:https://cloudbase.net

雲開發控制台:https://console.cloud.tencent.com/tcb?from=12304

更多精彩

掃描二維碼了解更多

繼續閱讀