captcha-web-sdk
v1.0.11
Published
Captcha browser SDK with browser-global and npm import support
Readme
captcha-web-sdk 验证码前端 SDK
| 条目 | | | -------- | ------------------------------------------------------------ | | 兼容性 | Chrome、Firefox、Safari、Opera、主流手机浏览器、iOS 及 Android上的内嵌Webview | | 框架支持 | H5、Angular、React、Vue2、Vue3、Next.js、React Native(WebView) |
本地打包
安装依赖
npm install执行 SDK 生产打包
npm run build发包前检查
npm run release:check打包产物在
dist目录下,核心文件如下:dist/tac/js/tac.min.jsdist/tac/css/tac.cssdist/tac/images/*
作为 SDK 接入
方式一: 浏览器 script 直引
<link rel="stylesheet" href="/tac/css/tac.css" />
<script src="/tac/js/tac.min.js"></script>
<div id="captcha-box"></div>
<script>
const tac = new TAC({
requestCaptchaDataUrl: "/gen",
validCaptchaUrl: "/check",
bindEl: "#captcha-box"
});
tac.init();
</script>方式二: npm 包方式引入
npm install captcha-web-sdkimport TAC, { CaptchaWebSdk, CaptchaConfig } from "captcha-web-sdk";
import "captcha-web-sdk/style.css";
const tac = new TAC({
requestCaptchaDataUrl: "/gen",
validCaptchaUrl: "/check",
bindEl: "#captcha-box"
});
tac.init();说明:
- 默认导出为
TAC,等价于CaptchaWebSdk - 仍然兼容浏览器全局变量
window.TAC和window.CaptchaConfig - 如果你还在使用历史的
load.min.js初始化方式,本仓库当前打包产物依然兼容该模式
配置参数表
构造函数签名:
const tac = new TAC(config, style);其中:
config是业务配置,负责接口地址、请求头、回调函数等style是展示配置,负责按钮、背景、logo、文案和字号等
1. config 参数表
| 参数名 | 类型 | 必填 | 默认值 | 说明 | 示例 |
| ------ | ---- | ---- | ------ | ---- | ---- |
| bindEl | string | 是 | 无 | 验证码挂载容器的选择器,必须能被 document.querySelector 找到 | "#captcha-box" |
| requestCaptchaDataUrl | string | 是 | 无 | 获取验证码数据的后端接口地址,SDK 默认用 POST + application/json 请求 | "/captcha/gen" |
| validCaptchaUrl | string | 是 | 无 | 提交验证码校验结果的后端接口地址,SDK 默认用 POST + application/json 请求 | "/captcha/check" |
| requestHeaders | Record<string, string> | 否 | {} | 发送到两个接口的公共请求头 | { Authorization: "Bearer xxx" } |
| timeToTimestamp | boolean | 否 | true | 是否自动把请求数据中的 Date 转成时间戳 | false |
| i18n | Partial<CaptchaI18nConfig> | 否 | 默认内置文案 | 运行时错误提示和状态文案覆盖配置 | { tips_error: "校验失败" } |
| validSuccess | (res, captcha, tac) => void | 否 | 默认打印日志并销毁窗口 | 验证成功回调 | (res, c, tac) => tac.destroyWindow() |
| validFail | (res, captcha, tac) => void | 否 | tac.reloadCaptcha() | 验证失败回调 | (res, c, tac) => tac.reloadCaptcha() |
| btnRefreshFun | (event, tac) => void | 否 | tac.reloadCaptcha() | 点击刷新按钮后的回调 | (e, tac) => tac.reloadCaptcha() |
| btnCloseFun | (event, tac) => void | 否 | tac.destroyWindow() | 点击关闭按钮后的回调 | (e, tac) => tac.destroyWindow() |
2. style 参数表
| 参数名 | 类型 | 必填 | 默认值 | 说明 | 示例 |
| ------ | ---- | ---- | ------ | ---- | ---- |
| btnUrl | string \| null | 否 | 内置 base64 按钮图 | 滑块按钮图片地址 | "https://cdn.example.com/btn.png" |
| bgUrl | string \| null | 否 | 无 | 验证码弹窗背景图地址 | "https://cdn.example.com/bg.jpg" |
| logoUrl | string \| null | 否 | 内置 logo | 底部 logo 地址,传 null 可隐藏 logo | null |
| moveTrackMaskBgColor | string | 否 | #89d2ff | 滑动轨道填充背景色 | "#f7b645" |
| moveTrackMaskBorderColor | string | 否 | #0298f8 | 滑动轨道边框颜色 | "#ef9c0d" |
| i18n | Partial<CaptchaI18nConfig> | 否 | 默认内置文案 | UI 文案和字号覆盖配置 | { slider_title: "请拖动滑块" } |
3. i18n 参数表
支持 %s 占位符的参数:
unknown_captcha_typetips_success
3.1 通用提示文案
| 参数名 | 默认值 | 用途 |
| ------ | ------ | ---- |
| required_bind_el | [TAC] 必须配置 [bindEl] 用于将验证码绑定到该元素上 | 缺少 bindEl 时抛出的错误文案 |
| required_request_captcha_data_url | [TAC] 必须配置 [requestCaptchaDataUrl] 请求验证码接口 | 缺少生成接口地址时抛出的错误文案 |
| required_valid_captcha_url | [TAC] 必须配置 [validCaptchaUrl] 验证验证码接口 | 缺少校验接口地址时抛出的错误文案 |
| invalid_captcha_data | [TAC] 后台验证码接口数据错误 | 获取验证码接口返回结构异常时的错误文案 |
| unknown_captcha_type | [TAC] 未知的验证码类型[%s] | 后端返回未知验证码类型时的错误文案 |
| default_valid_success_log | 验证码校验成功,请重写 [config.validSuccess] 方法,用于自定义逻辑处理 | 未自定义成功回调时的默认日志文案 |
| tips_success | 验证成功,耗时%s秒 | 验证成功的提示文案 |
| tips_error | 验证失败,请重新尝试! | 普通失败提示文案 |
| tips_4001 | 验证码已失效,请刷新后重试! | 验证码失效提示文案 |
| tips_network_error | 网络异常,请稍后重试! | 网络异常提示文案 |
3.2 UI 文案与字号
| 参数名 | 默认值 | 用途 |
| ------ | ------ | ---- |
| modal_title | 请完成安全验证 | 弹窗头部主标题 |
| modal_subtitle | 验证通过后即可继续操作 | 弹窗头部副标题 |
| close_button_aria_label | 关闭验证 | 关闭按钮无障碍文案 |
| slider_title | 拖动滑块完成拼图 | 历史滑块任务说明文案,当前默认 UI 不再展示,保留兼容 |
| slider_action_hint | 按住滑块,拖动完成上方拼图 | 滑块验证码轨道提示文案 |
| concat_title | 拖动滑块完成拼图 | 历史拼接任务说明文案,当前默认 UI 不再展示,保留兼容 |
| concat_action_hint | 按住滑块,拖动完成上方拼图 | 拼接验证码轨道提示文案 |
| image_click_title | 请依次点击: | 点选验证码标题 |
| image_click_confirm_text | 确定 | 点选验证码确认按钮文案 |
| rotate_title | 拖动滑块完成拼图 | 历史旋转任务说明文案,当前默认 UI 不再展示,保留兼容 |
| rotate_action_hint | 按住滑块,旋转至正确角度 | 旋转验证码轨道提示文案 |
| disable_title | 当前验证码不可用 | 禁用态标题 |
| disable_default_message | 接口异常 | 禁用态默认提示 |
| slider_title_size | 15px | 滑块验证码标题字号 |
| concat_title_size | 15px | 拼接验证码标题字号 |
| image_click_title_size | 20px | 点选验证码标题字号 |
| rotate_title_size | 15px | 旋转验证码标题字号 |
| disable_title_size | 15px | 禁用态标题字号 |
3.3 已废弃但兼容保留的 i18n 字段
| 参数名 | 当前状态 | 说明 |
| ------ | -------- | ---- |
| close_text | 已废弃,但仍兼容 | 会自动映射到 close_button_aria_label,建议改用新字段 |
| refresh_text | 已废弃,当前忽略 | 刷新按钮已改为纯 icon 交互,不再显示该文案 |
4. 高级能力: 请求链 requestChain
如果你要在请求前后统一加签名、改请求体、打印日志,可以使用 CaptchaConfig 实例上的请求链能力。
| 方法名 | 参数 | 说明 |
| ------ | ---- | ---- |
| addRequestChain(chain) | { preRequest?, postRequest? } | 在链尾追加一个处理器 |
| insertRequestChain(index, chain) | index, chain | 在指定位置插入处理器 |
| removeRequestChain(index) | index | 删除指定位置的处理器 |
请求链回调签名:
| 回调 | 签名 | 说明 |
| ---- | ---- | ---- |
| preRequest | (type, requestParam, config, captcha, tac) => boolean \| void | 请求发送前执行,可修改 requestParam |
| postRequest | (type, requestParam, response, config, captcha, tac) => boolean \| void | 请求完成后执行,可统一处理返回结果 |
type 可能值:
requestCaptchaDatavalidCaptcha
requestParam 结构:
{
url: "/captcha/gen",
method: "POST",
headers: {
"Content-Type": "application/json;charset=UTF-8"
},
data: {}
}5. 最小可用配置
import TAC from "captcha-web-sdk";
import "captcha-web-sdk/style.css";
const tac = new TAC({
bindEl: "#captcha-box",
requestCaptchaDataUrl: "/captcha/gen",
validCaptchaUrl: "/captcha/check"
});
tac.init();6. 完整配置示例
import TAC from "captcha-web-sdk";
import "captcha-web-sdk/style.css";
const tac = new TAC(
{
bindEl: "#captcha-box",
requestCaptchaDataUrl: "/captcha/gen",
validCaptchaUrl: "/captcha/check",
requestHeaders: {
Authorization: "Bearer your-token"
},
timeToTimestamp: true,
i18n: {
tips_error: "验证失败,请重新再试一次",
tips_network_error: "网络开小差了,请稍后重试"
},
validSuccess: (res, captcha, tacInstance) => {
tacInstance.destroyWindow();
console.log("校验成功:", res);
},
validFail: (res, captcha, tacInstance) => {
tacInstance.reloadCaptcha();
},
btnRefreshFun: (event, tacInstance) => {
tacInstance.reloadCaptcha();
},
btnCloseFun: (event, tacInstance) => {
tacInstance.destroyWindow();
}
},
{
logoUrl: null,
btnUrl: "https://cdn.example.com/captcha/btn.png",
bgUrl: "https://cdn.example.com/captcha/bg.jpg",
moveTrackMaskBgColor: "#f7b645",
moveTrackMaskBorderColor: "#ef9c0d",
i18n: {
slider_title: "拖动滑块完成验证",
slider_action_hint: "向右拖动完成验证",
modal_title: "请完成下列验证后继续",
modal_subtitle: "验证成功后会自动返回当前流程",
close_button_aria_label: "关闭验证码弹窗",
image_click_confirm_text: "确认"
}
}
);
tac.init();国际化配置
现在支持两种国际化覆盖方式:
config.i18n: 适合接口提示、运行时错误等文案style.i18n: 适合按钮、标题、禁用态等 UI 文案
两者都会和默认文案自动合并,style.i18n 优先级最高。
import TAC from "captcha-web-sdk";
import "captcha-web-sdk/style.css";
const tac = new TAC(
{
requestCaptchaDataUrl: "/gen",
validCaptchaUrl: "/check",
bindEl: "#captcha-box",
i18n: {
required_bind_el: "[TAC] bindEl is required",
required_request_captcha_data_url: "[TAC] requestCaptchaDataUrl is required",
required_valid_captcha_url: "[TAC] validCaptchaUrl is required",
invalid_captcha_data: "[TAC] Invalid captcha payload",
unknown_captcha_type: "[TAC] Unknown captcha type[%s]",
tips_success: "Verified in %s seconds",
tips_error: "Verification failed, please try again",
tips_4001: "Captcha expired, please refresh and retry",
tips_network_error: "Network error, please try again later"
},
validSuccess: (res, c, tacInstance) => {
tacInstance.destroyWindow();
console.log("captcha ok", res);
}
},
{
i18n: {
modal_title: "Please complete the verification",
modal_subtitle: "Continue after the verification passes",
close_button_aria_label: "Close verification",
slider_title: "Drag the slider to complete the puzzle",
slider_action_hint: "Hold the handle and drag to complete the puzzle",
concat_title: "Drag the slider to complete the puzzle",
concat_action_hint: "Hold the handle and drag to complete the puzzle",
image_click_title: "Click in order:",
image_click_confirm_text: "Confirm",
rotate_title: "Drag the slider to rotate",
rotate_action_hint: "Hold the handle and rotate to the correct angle",
disable_title: "Captcha unavailable",
disable_default_message: "Request failed"
}
}
);
tac.init();最近变更
本次 SDK UI 与国际化做了以下调整:
- 统一滑块类验证码的信息层级:头部
modal_title / modal_subtitle作为主标题区,内部slider_title / concat_title / rotate_title调整为图片区上方的任务说明 - 重做
SLIDER / CONCAT / ROTATE三类滑块轨道,统一为更接近系统控件的浅底轨道、实体把手和完整蓝色进度底块 - 滑块类验证码已移除图片区上方的额外任务说明行,避免与头部主标题重复;
slider_title / concat_title / rotate_title当前仅兼容保留 - 新增弹窗头部文案国际化:
modal_title、modal_subtitle - 新增关闭按钮无障碍文案国际化:
close_button_aria_label - 新增滑块轨道提示国际化:
slider_action_hint、concat_action_hint、rotate_action_hint - 刷新按钮调整为纯 icon 形式,
refresh_text不再展示 - 刷新按钮点击时增加旋转动画反馈
- 关闭按钮与刷新按钮都改为纯 icon 交互样式
- 弹窗整体圆角和字号已收敛,视觉更贴近用户端业务场景
兼容性说明:
- 旧字段
close_text仍会自动兼容到close_button_aria_label - 旧字段
refresh_text不会报错,但当前 UI 已不再使用该文案
多框架示例
完整示例见 examples/frameworks.md
- Next.js: 仅在 Client Component 中初始化,CSS 放到
app/layout.tsx或pages/_app.tsx - React: 在
useEffect中初始化,在清理函数里销毁 - Vue3: 在
onMounted中初始化,在onBeforeUnmount中销毁 - Vue2: 在
mounted中初始化,在beforeDestroy中销毁 - React Native: 通过
react-native-webview加载 H5 页面或内联 HTML,不支持直接在原生运行时中挂载 DOM 版 SDK
发布到 npm
首次发布前
登录 npm
npm login确认包名还未被占用
npm view captcha-web-sdk version如果返回
404 Not Found,说明当前包名还没有被注册。执行发包前检查
npm run release:check
手动发布
npm publishCI 自动发布
仓库内已提供 GitHub Actions 工作流:
- 推送
v*标签时自动发布 - 也支持手动触发
workflow_dispatch
如果你的源码仓库托管在 Gitee,.github/workflows 不会自动执行,需要将同样的步骤迁移到 Gitee Go 或其他 CI 平台。
使用前需要在仓库 Secrets 中配置:
NPM_TOKEN
示例发布命令:
git tag v1.0.0
git push origin v1.0.0旧版 load.min.js 兼容接入
如果你还在使用历史初始化方式,也可以继续通过 window.initTAC 接入。推荐优先迁移到上文的 npm / new TAC(...) 方式,便于类型提示、打包优化和长期维护。
<div id="captcha-box"></div>
<script src="/tac/load.min.js"></script>
<script>
const config = {
requestCaptchaDataUrl: "/gen",
validCaptchaUrl: "/check",
bindEl: "#captcha-box",
i18n: {
tips_error: "验证失败,请重试"
}
};
const style = {
logoUrl: null,
i18n: {
modal_title: "请完成安全验证",
modal_subtitle: "验证通过后即可继续操作",
close_button_aria_label: "关闭验证",
slider_action_hint: "按住滑块,拖动完成上方拼图"
}
};
window.initTAC("/tac", config, style).then((tac) => {
tac.init();
});
</script>