藉助臨時CDN傳遞大數據到雲函數實現圖片安全檢測
最近在重構小程序戀愛小清單,在用雲函數做圖片的安全檢測時報了一個錯:cloud.callFunction:fail Error: data exceed max size
也就是圖片超過了大小限制。
早期的版本是通過畫布將圖片縮小(wx.canvasToTempFilePath),接着讀取文件流(wx.getFileSystemManager().readFile),然後再提交雲函數檢測,過程感覺有些繁瑣複雜
最近發現其實有更簡單的方法,可以藉助臨時的CDN,傳遞大數據,最終在雲函數端會收到一個CDN地址,接着通過request-promise讀取文件流,然後再做安全檢測,相比舊版的方法個人感覺簡單清爽不少。
參考官方文檔:
https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/utils/Cloud.CDN.html
代碼如下:
小程序端:
const api = require("api.js");
/**
* 圖片安全檢測
* 藉助臨時CDN傳遞大數據
* @param filePath 圖片的臨時文件路徑 (本地路徑)
* @returns {Promise<unknown>}
*/
const imgSecCheckViaCDN = (filePath) => {
return new Promise(function (resolve, reject) {
api.callCloudFunction("securityCheck", {
type: "imgSecCheckViaCDN",
imgData: wx.cloud.CDN({
type: "filePath",
filePath,
})
}, res => {
console.log("圖片安全檢測結果:", JSON.stringify(res));
const result = res.result;
if (result.success) {
resolve(result);
} else {
reject(result);
}
}, reject);
});
}
api.js
/**
* 雲函數調用
* @param name
* @param data
* @param success
* @param fail
* @param complete
*/
const callCloudFunction = function (name, data, success, fail, complete) {
//執行雲函數
wx.cloud.callFunction({
// 雲函數名稱
name: name,
// 傳給雲函數的參數
data: Object.assign({}, data, {env: env.activeEnv})
}).then(res => {
typeof success == 'function' && success(res);
}).catch(res => {
typeof fail == 'function' && fail(res);
}).then(res => {
typeof complete == 'function' && complete(res);
});
};
module.exports = {callCloudFunction}
雲函數端:
// 雲函數入口文件
const cloud = require('wx-server-sdk');
const responce = require('easy-responce');
const requestHelper = require('./utils/requestHelper');
const headers = {
encoding: null,
headers: {
"content-type": "application/octet-stream",
// "content-type": "video/mpeg4",
},
};
// 雲函數入口函數
exports.main = async (event, context) => {
cloud.init({
env: event.env
});
let result = {};
try {
const {type, content, imgData} = event;
let {buffer} = event;
console.log("檢測類型:", type, "文本內容:", content, "圖片內容:", imgData);
switch (type) {
case "imgSecCheckViaCDN":
const imageResponse = await requestHelper.request(imgData, headers, {});
buffer = imageResponse.body;
case "imgSecCheck":
result = await cloud.openapi.security.imgSecCheck({
media: {
contentType: 'image/png',
// value: Buffer.from(imgBase64, "base64")
value: Buffer.from(buffer)
}
});
break;
case "msgSecCheck":
result = await cloud.openapi.security.msgSecCheck({content});
break;
default:
console.log("不支持的檢測類型:", type);
break;
}
} catch (e) {
console.error(e);
result = e;
}
console.log("檢測結果:", result);
const {errCode, errMsg} = result;
return errCode !== 87014 ? responce.success({errCode}) : responce.fail(errMsg);
};
requestHelper.js
const rp = require('request-promise');
/**
* http請求
* @param url
* @param options
* @param data
* @param autoFollowRedirect
* @returns {Promise<unknown>}
*/
const request = function (url, options, data, autoFollowRedirect = true) {
return new Promise(function (resolve, reject) {
const p = Object.assign({
json: true,
resolveWithFullResponse: true,
followRedirect: autoFollowRedirect
}, options, data, {url});
console.log("請求參數:", JSON.stringify(p));
return rp(p)
.then(async function (repos) {
//console.log("獲取到最終內容,執行回調函數:", repos);
return resolve(repos);
})
.catch(async function (err) {
if (err && (err.statusCode === 301 || err.statusCode === 302)) {
// console.log("停止重定向,重定向信息:", err);
console.log("停止重定向");
return resolve(err);
}
console.error("重定向失敗:", err);
return reject(err);
});
});
}
module.exports = {request }