以前,公司项目一直使用腾讯云的TCaptcha.js实现图形验证,简单方便(TCaptcha.js官方文档)。但它是需要按次计费的,这回,项目组领导准备找一个免费的,最终天爱验证码TIANAI-CAPTCHA被选中。后端实现我就不提了,开发人员可自行去查阅 TIANAI-CAPTCHA文档,作为前端开发人员,我会将自己前端开发过程中遇到和实践成功的方案记录下来,方便以后查阅和使用。
TIANAI-CAPTCHA的文档中,是有记录前端使用方法的,按照它的叙述,应该是能快速使用起来的。 可查看 TIANAI-CAPTCHA文档 或者 天爱有情/tianai-captcha-web-sdk,它们介绍了如何将天爱图形验证码如何引入项目,以及使用方法,如下图:
为了方便记录和描述,TIANAI-CAPTCHA后面就简称tac了。
如果你开发的是webpack构建的vue2项目,或者传统的前端项目,或许你能很容易就使用它,不会遇到啥问题,比如webpack搭建的vue2项目,里面是有public目录的,index.html也包含其中,我们按照文档,应该一切OK(我没有实践,或许能出问题也不一定,大家可以去试一试)。不过我们当时使用的是vite构建的vue2项目,里面是没有public文件夹的。
上面的文档中曾提到,将打包好的tac目录放到public目录中、或者放到某个可以访问到地方,比如oss之类的可以被浏览器访问到的地方。
因为没有public,起初我将tac放到了src下,不管如何尝试,最终都失败了,稍后我会将问题记录在后文其他问题中,有兴趣的可以看看,下面我先介绍下成功实践后的两种方案。
如何安装
方案一:
1、将打包好的tac目录整个拷贝到vue项目根目录,找到根目录下的index.html,在头部head中引入load.min.js,
<script type="module" src="./tac/js/load.min.js"></script>
2、下载 rollup-plugin-copy,
npm install rollup-plugin-copy --save-dev
3、打开 vite.config.js ,在build中加入以下配置:
import copyPlugin from 'rollup-plugin-copy'
export default defineConfig(({ mode }) =>{
return {
build: {
rollupOptions: {
plugins: [
copyPlugin({
targets: [{ src: 'tac/*', dest: 'dist/tac' }],
hook: 'writeBundle'
}),
],
},
// outDir: 'dist',
// assetsDir: 'assets',
},
}
})
上方代码实现了将整个tac目录及其里面文件拷贝到打包生成的dist目录中。
一定要注意 hook: 'writeBundle' ,这段代码很关键,如果没有这段代码,你会发现,在我们打包生成的dist目录中,并没有找到tac,可这是为什么呢?
其实在打包的时候,拷贝动作已经执行成功在dist中生成tac了,但是很快又被删除了。在执行npm run build的打包过程中,开始有一个过程,就是先清空dist中的所有文件,然后才会执行打包生成文件到dist中。如果没有hook这个命令,拷贝动作一早就执行,很快就会被清空这一动作搞没了。所以这下清楚了吧。
在构建流程中,vite继承了Rollup 的 writeBundle 钩子为部署环节提供的深度扩展能力。通过 writeBundle钩子,可在打包完成后自动触发。我把它当成了writeAfterBundleComplete or writeAfterBundleEnd 的缩写,你觉得呢?
hook: 'writeBundle' 用起来是真的香。
方案二:
1、将打包好的tac目录整个部署到服务器上,使其能正常访问tac中的文件(这一步很关键,是后面步骤的先决条件);
2、在各个环境配置文件中配置能访问tac目录的地址变量 VITE_APP_TAC_API,比如开发环境中.env.test
# 接口域名
VITE_APP_API_ORIGIN = 测试环境域名
# 接口前缀(项目命名空间)
VITE_APP_API_PREFIX = /standard-onetravel
# tianai-captcha前端包访问地址
VITE_APP_TAC_API = ${VITE_APP_API_ORIGIN}${VITE_APP_API_PREFIX}/tac
3、下载vite-plugin-html,在vite.config.js中配置能在index.html中正常访问tac目录的变量 appTacApi
npm install vite-plugin-html --save-dev
import { createHtmlPlugin } from "vite-plugin-html";
// 获取指定环境变量值
const getViteEnv = (mode, target) => {
return loadEnv(mode, process.cwd())[target];
};
export default defineConfig(({ mode }) =>{
return {
plugins: [
createHtmlPlugin({
inject: {
data: {
appTacApi:getViteEnv(mode, "VITE_APP_TAC_API")
},
},
}),
]
}
}
4、index.html的头部head中引入 load.min.js
<script src="<%- appTacApi %>/js/load.min.js"></script>
问题: 为什么不省略第3和4步骤,直接写死tac的访问地址呢?
我们的项目有最少开发、测试、生产3个环境,每个环境域名都不同,甚至有时候各个环境命名空间也不同,生产还可能是第三方的,直接写死,怎么知道其他环境的地址,并且保证能正常访问。如果是第三方,我们总不能让生产访问我们的服务器啥的tac文件吧,何况项目开发时可能还没第三方的地址呢?总不能写死每遇到一个环境都去更改项目中的代码吧!
以上两个方案,推荐使用方案一,我们不必去关注它部署在哪个环境,因为tac已经集成到了项目中。
如何应用
上面的准备工作都做好了,又该如何使用呢?
使用的时候,我们当然就可以像文档中提到的那样使用了,唯一需要注意的就是 tac文件目录地址
使用方案一:
为了在调试阶段和服务器上都能正常访问,tac文件目录地址 我使用了 location.href截取拼接
const tacUrl = location.href.split("#")[0]+'tac'
使用方案二:
tac必须事先部署到服务器,tac文件目录地址直接取值变量 VITE_APP_TAC_API即可
const tacUrl = import.meta.env.VITE_APP_TAC_API
具体使用如下:
const baseUrl = `${import.meta.env.VITE_APP_BASE_API}/sot-admin-api`;
const config = {
requestCaptchaDataUrl: `${baseUrl}/captcha/gen`,
validCaptchaUrl: `${baseUrl}/captcha/check`,
bindEl: "#captcha-box",
// 验证成功回调函数(必选项,必须配置)
validSuccess: (res, c, tac) => {
// 销毁验证码服务
tac.destroyWindow();
// console.log("验证成功,后端返回的数据为", res);
this.$emit("adopt", {});
},
// 验证失败的回调函数(可忽略,如果不自定义 validFail 方法时,会使用默认的)
validFail: (res, c, tac) => {
console.log("验证码验证失败回调...");
// 验证失败后重新拉取验证码
tac.reloadCaptcha();
},
// 刷新按钮回调事件
btnRefreshFun: (el, tac) => {
console.log("刷新按钮触发事件...");
tac.reloadCaptcha();
},
// 关闭按钮回调事件
btnCloseFun: (el, tac) => {
console.log("关闭按钮触发事件...");
tac.destroyWindow();
},
};
const style = {
// logo地址
logoUrl: null,
// // 按钮样式
// btnUrl: "https://minio.tianai.cloud/public/captcha-btn/btn3.png",
// // 背景样式
// bgUrl: "https://minio.tianai.cloud/public/captcha-btn/btn3-bg.jpg",
// 滑动边框样式
// moveTrackMaskBgColor: "#f7b645",
// moveTrackMaskBorderColor: "#ef9c0d",
};
const tacUrl = location.href.split("#")[0]+'tac'
window
.initTAC(tacUrl, config, style)
.then((tac) => {
this.captcha = tac;
})
.catch((e) => {
console.log("初始化tianai-captcha失败", e);
});
其他问题
1、打包好的tac如何获取?
下载 tianai-captcha-demo ,找到目录
src/main/resources/static,拷贝 static 并改名为tac即可。
2、为什么使用tac这么麻烦,没有腾讯云TCaptcha.js方便?
其实源头还在tac的作者在文档中推荐的前端使用方法,让我们引入的load.min.js上,
load.min.js 没有提供 未压缩版本,不过从加载进来的代码我们可以看到
我们使用的函数 initTAC 就是从 load.min.js 中 来的
window.initTAC = initTAC;
而使用的initTAC 函数, 又根据我们使用时传入的 tac文件目录地址 变量值,对 tac.min.js 和 tac.css 的访问地址进行了重新赋值,
然后加载tac的js和css。就是这坑爹的一个步骤,导致加载tac的js和css失败,从而出现其他各种使用方式使用tac失败的情况。
比如直接引用文档中提供的地址:
<script src="https://minio.tianai.cloud/public/static/captcha/js/load.min.js"></script>
使用initTAC时的第一个参数 tac文件目录地址,如果你传 './tac'等值,都会导致出现下面的报错,
看到这里,或许有人想说,你在index.html的头部引入天爱的CDN链接
<script src="https://minio.tianai.cloud/public/static/captcha/js/load.min.js"></script>
然后使用initTAC方法时, tac文件目录地址
const tacUrl = 'https://minio.tianai.cloud/public/static/captcha/'
window.initTAC(tacUrl, config, style)
.then((tac) => {
this.captcha = tac;
})
.catch((e) => {
console.log("初始化tianai-captcha失败", e);
});
这样,拼接的tac.css和tac.min.js都能正常加载不会报错,很高兴你能想到这一点,这种方案我也尝试了(使用方案一和方案二都正常,后端接口也OK的情形下),很遗憾的是,图形验证码都出来了,可后端接口 /check (initTAC中第二个参数config.validCaptchaUrl )却又报错了
是不是有种骂人的冲动,可千万别。反正试错这一步我已经走过了,你不想麻烦,也没必要试错了不是。
这里介绍的是后台项目中天爱验证码的使用,如果您想在小程序中使用天爱验证码,又不想慢慢研究的,可查看我的这篇文章 微信小程序中封装天爱验证码 ,好了,大家能看我啰嗦到这里,不胜感激。