本来用小程序写了一个本地化的图片应用,不存在服务端的交互行为
结果提交审核的时候还是被打回了
好的!马上整改
应用的交互大概就是这样
我们需要在选择图片后
对图片做一次安全校验
启用云开发
现在我们需要一个 后端接口 来实现图片的 安全校验 功能
这时候临时搭个Node服务好像不太现实
又不是什么正经项目
于是就想到了微信的云开发功能
用起来真实方便快捷
至于图片的校验方法
直接用云函数调用 security.imgSecCheck 接口就好了
流程
chooseImage() {
/// 用户选择图片
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: async res => {
if (res.errMsg === 'chooseImage:ok') {
wx.showLoading({ title: '图片加载中' })
// 获取图片临时地址
const path = res.tempFilePaths[0]
// 将图片地址实例化为图片
const image = await loadImage(path, this.canvas)
// 压缩图片
const filePath = await compress.call(this, image, 'canvas_compress')
// 校验图片合法性
const imgValid = await checkImage(filePath)
wx.hideLoading()
if (!imgValid) return
// 图片安全检测通过,执行后续操作
...
}
})
}
图片压缩
由于 security.imgSecCheck 对图片有尺寸限制
所以在图片上传前要先对超出尺寸的图片进行压缩处理
基本逻辑就是
超出尺寸的图片等比例缩小就好了
我们先要有一个canvas元素
用来处理需要压缩的图片
<template>
<view class="menu-background">
<view class="item replace" bindtap="chooseImage">
<i class="iconfont icon-image"></i>
<text class="title">图片</text>
<text class="sub-title">图片仅供本地使用</text>
</view>
//
// canvas
//
<canvas
type="2d"
id="canvas_compress"
class="canvas-compress"
style="width: {{canvasCompress.width}}px; height: {{canvasCompress.height}}px"
/>
</view>
</template>
将canvas移到视野不可见到位置
.canvas-compress
position absolute
left 0
top 1000px
图片进行压缩处理
/**
* 压缩图片
* 将尺寸超过规范的图片最小限度压缩
* @param {Image} image 需要压缩的图片实例
* @param {String} canvasId 用来处理压缩图片的canvas对应的canvasId
* @param {Object} config 压缩的图片规范 -> { maxWidth 最大宽度, maxHeight 最小宽度 }
* @return {Promise} promise返回 压缩后的 图片路径
*/
export default function (image, canvasId, config = { maxWidth: 750, maxHeight: 1334 }) {
// 引用的组件传入的this作用域
const _this = this
return new Promise((resolve, reject) => {
// 获取图片原始宽高
let width = image.width
let height = image.height
// 宽度 > 最大限宽 -> 重置尺寸
if (width > config.maxWidth) {
const ratio = width / config.maxWidth
width = config.maxWidth
height = height / ratio
}
// 高度 > 最大限高度 -> 重置尺寸
if (height > config.maxHeight) {
const ratio = height / config.maxHeight
height = config.maxHeight
width = width / ratio
}
// 设置canvas的css宽高
_this.canvasCompress.width = width
_this.canvasCompress.height = height
const query = this.createSelectorQuery()
query
.select(`#${canvasId}`)
.fields({ node: true, size: true })
.exec(async res => {
// 获取 canvas 实例
const canvas = res[0].node
// 获取 canvas 绘图上下文
const ctx = canvas.getContext('2d')
// 根据设备dpr处理尺寸
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = width * dpr
canvas.height = height * dpr
ctx.scale(dpr, dpr)
// 将图片绘制到 canvas
ctx.drawImage(image, 0, 0, width, height)
// 将canvas图片上传到微信临时文件
wx.canvasToTempFilePath({
canvas,
x: 0,
y: 0,
destWidth: width,
destHeight: height,
complete (res) {
if (res.errMsg === 'canvasToTempFilePath:ok') {
// 返回临时文件路径
resolve(res.tempFilePath)
}
},
fail(err) {
reject(err)
}
})
})
})
}
图片安全校验
云函数 checkImage.js
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
/**
* 校验图片合法性
* @param {*} event.fileID 微信云存储的图片ID
* @return {Number} 0:校验失败;1:校验通过
*/
exports.main = async (event, context) => {
const contentType = 'image/png'
const fileID = event.fileID
try {
// 根据fileID下载图片
const file = await cloud.downloadFile({
fileID
})
const value = file.fileContent
// 调用 imgSecCheck 借口,校验不通过接口会抛错
// 必要参数 media { contentType, value }
const result = await cloud.openapi.security.imgSecCheck({
media: {
contentType,
value
}
})
return 1
} catch (err) {
return 0
}
}
组件调用云函数封装
/**
* 校验图片是否存在敏感信息
* @param { String } filePath
* @return { Promise } promise返回校验结果
*/
export default function (filePath) {
return new Promise((resolve, reject) => {
// 先将图片上传到云开发存储
wx.cloud.uploadFile({
cloudPath: `${new Date().getTime()}.png`,
filePath,
success (res) {
// 调用云函数-checkImage
wx.cloud.callFunction({
name: 'checkImage',
data: {
fileID: res.fileID
},
success (res) {
// res.result -> 0:存在敏感信息;1:校验通过
resolve(res.result)
if (!res.result) {
wx.showToast({
title: '图片可能含有敏感信息, 请重新选择',
icon: 'none'
})
}
},
fail (err) {
reject(err)
}
})
},
fail (err) {
reject(err)
}
})
})
}
本文demo
本文代码仓库
https://github.com/luosijie/f...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。