需求背景
这天,主管找到我:"有个微信小程序的验证码接口被恶意调用,一天刷了几百条,你看能不能加一个验证码限制一下"。我一听,终于来活了,直接开搞。
需求分析
公司一直有订阅阿里云验证码2.0服务,看文档微信小程序刚好能用,就直接用它,先登录验证码2.0控制台新建验证场景、填写配置,然后登录微信小程序后台添加插件,等申请通过就能用了。
开始接入
在app.json中声明插件
            
            
              json
              
              
            
          
          "plugins": {
      "AliyunCaptcha": {
      "version": "2.1.1",
      "provider": "wxbe275ff84246f1a4"
    }
}引入验证码小程序组件
            
            
              json
              
              
            
          
          {
  "usingComponents": {
    "aliyun-captcha": "plugin://AliyunCaptcha/captcha"
  }
}模板插入
            
            
              html
              
              
            
          
          <aliyun-captcha id="captcha-element" wx:if="{{loadCaptcha}}" props="{{pluginProps}}" />插件初始化
            
            
              js
              
              
            
          
          // ali-captcha.js
import { postCode } from '../../service/api';
const AliyunCaptchaPluginInterface = requirePlugin('AliyunCaptcha');
const INTERVAL = 100;
// 业务请求(带验证码校验)回调函数
export const captchaVerifyCallback = async function (captchaVerifyParam) {
    try {
      const result = await postCode({ ali_captcha_verify_param: captchaVerifyParam, phone: this.data.phone });
      return {
        captchaResult: result.data.ali_verify_captcha,
        bizResult: result.data.ali_verify_captcha,
      };
    } catch (error) {
      AliyunCaptchaPluginInterface.refresh();
    }
  };
  // 业务请求验证结果回调函数
export const onBizResultCallback = function (bizResult) {
    if (bizResult === true) {
      let time = setInterval(() => {
        let {
            countInterval
        } = this.data;
        if (countInterval <= 1) {
            clearInterval(time);
            this.setData({
                countInterval: INTERVAL,
                codeBtnText: '重新获取'
            });
            return;
        }
        countInterval--
        this.setData({
            countInterval,
            codeBtnText: `${countInterval}s`
        })
    }, 1000)
    } else {
      wx.showToast({
        title: '业务验证不通过!',
        duration: 2000,
        icon: 'error',
      });
    }
  };
            
            
              js
              
              
            
          
          // 主要代码
import { captchaVerifyCallback, onBizResultCallback } from 'ali-captcha.js';
const AliyunCaptchaPluginInterface = requirePlugin('AliyunCaptcha');
onLoad() {
    const pluginProps = {
        SceneId: '',
        mode: 'popup',
        captchaVerifyCallback: captchaVerifyCallback.bind(this),
        onBizResultCallback: onBizResultCallback.bind(this),
        slideStyle: {
          width: 540,
          height: 60,
        },
        language: 'cn',
        region: 'cn',
      };
      getCaptchaConfig().then((res) => {
        pluginProps.SceneId = res.data.scene_id;
        this.setData({
          loadCaptcha: true,
          pluginProps,
        });
      }).catch(err=>{
        wx.showToast({
            title: '获取验证码配置失败',
            icon: 'none',
            duration: 3000
        })
      })
},
getCodeHandle() {
    // 表单校验
    AliyunCaptchaPluginInterface.show();
}开始分包
写好,测试,没问题,提CR,结果

居然把插件放在主包了,马上改,使用分包异步化+占位组件
文档:在小程序中,不同的分包对应不同的下载单元;因此,除了非独立分包可以依赖主包外,分包之间不能互相使用自定义组件或进行 require。「分包异步化」特性将允许通过一些配置和新的接口,使部分跨分包的内容可以等待下载后异步使用,从而一定程度上解决这个限制。
将插件封装为一个单独的组件
            
            
              json
              
              
            
          
          {
    "component": true,
    "usingComponents": {
        "aliyun-captcha": "plugin://AliyunCaptcha/captcha"
    }
}
            
            
              js
              
              
            
          
          import { getCaptchaConfig, postCode } from '../../service/api';
const AliyunCaptchaPluginInterface = requirePlugin('AliyunCaptcha');
// 业务请求(带验证码校验)回调函数
const captchaVerifyCallback = async function (captchaVerifyParam) {
    try {
      const result = await postCode({ ali_captcha_verify_param: captchaVerifyParam, phone: this.data.phone });
      return {
        captchaResult: result.data.ali_verify_captcha,
        bizResult: result.data.ali_verify_captcha,
      };
    } catch (error) {
        AliyunCaptchaPluginInterface.refresh();
    }
  };
// 业务请求验证结果回调函数
const onBizResultCallback = function (bizResult) {
    if (bizResult === true) {
        this.triggerEvent('changeCodeBtnState');
    } else {
        wx.showToast({
        title: '业务验证不通过!',
        duration: 2000,
        icon: 'error',
        });
    }
};
Component({
    lifetimes: {
        attached: function () {
            const pluginProps = {
                SceneId: '',
                mode: 'popup',
                captchaVerifyCallback: captchaVerifyCallback.bind(this),
                onBizResultCallback: onBizResultCallback.bind(this),
                slideStyle: {
                  width: 540,
                  height: 60,
                },
                language: 'cn',
                region: 'cn',
              }
            getCaptchaConfig().then((res) => {
                pluginProps.SceneId = res.data.scene_id;
                this.setData({
                  loadCaptcha: true,
                  pluginProps,
                });
              }).catch(()=>{
                wx.showToast({
                    title: '获取验证码配置失败',
                    icon: 'none',
                    duration: 3000
                })
              })
        }
    },
    properties: {
        phone: {
          type: String,
          value: ''
        }
    },
    data: {
    },
    methods: {
      show() {
        AliyunCaptchaPluginInterface.show();
      }
    }
})
            
            
              html
              
              
            
          
          <aliyun-captcha id="captcha-element" wx:if="{{loadCaptcha}}" props="{{pluginProps}}" />将其设置为一个单独的分包:
            
            
              json
              
              
            
          
          // app.json
{
  "root": "pkg-plugin",
  "pages": [
    "ali-captcha/ali-captcha"
  ],
  "plugins": {
      "AliyunCaptcha": {
      "version": "2.1.1",
      "provider": "wxbe275ff84246f1a4"
    }
  }
}分包完成,在需要用到的页面中使用
            
            
              json
              
              
            
          
          // login.json
{
    "navigationBarTitleText": "登录",
    "usingComponents": {
      "captcha": "/pkg-plugin/ali-captcha/ali-captcha"
    },
    "componentPlaceholder": {
      "captcha": "view"
    }
}
            
            
              html
              
              
            
          
          <-- login.wxml -->
<captcha class="aliCaptcha" phone="{{ phone }}" bind:changeCodeBtnState="changeCodeBtnState" />
            
            
              js
              
              
            
          
          // login.js
// 处理表单校验等业务参考: