分享经验 版主:论坛审计组
迅睿CMS网站多表单全套Token、验证码、下载踩坑汇总
类型:迅睿框架 更新时间:2026-07-16 15:56:54 验证码错误 表单验证码 浏览器缓存 自定义资料

【经验分享】迅睿CMS(V4.7.2) 自定义资料下载弹窗AJAX 表单全套踩坑汇总(Token / 验证码 / 下载 / 流量封禁)

 

一、版本环境

迅睿 CMS 版本:V4.7.2

场景:产品列表自定义资料下载弹窗,手写 AJAX 提交表单,页面同时存在底部留言、快速报价多套表单

 

二、第一大坑:CSRF Token 无限制递归,疯狂刷请求触发 WAF/EdgeOne 流量封顶

 

1、故障现象

页面长时间停留后 CSRF Token 过期,后端接口返回 res.token;前端无重试次数限制,拿到 token 直接递归调用提交函数,瞬间批量 POST 请求,被 WAF 判定 CC 攻击,弹窗提示「网络异常」,CDN 用量快速达到告警阈值,严重会站点 418 封禁。

 

2、错误危险代码(社区可直接贴纯文本代码块)

<js>

success:function(res){

  if(res.token){

    // 无任何次数限制,无限循环发起POST请求

    updateToken(res.token);

    submitZlsqForm();

    return;

  }

}

 

3、根因

没有全局提交锁、没有 token 最大重试计数器,单次 token 失效就死循环刷接口。

 

4、标准修复方案(遵循官方 BOSS 给出的 Token 处理规范)

新增全局变量:提交锁 submitLock、最大重试次数 retryMax=1、重试计数 retryCount

提交前上锁,请求完成解锁,防止重复点击;

token 仅允许自动重试 1 次,超出则走失败提示;

正确读取 res.token 子对象,兼容页面无 token 隐藏域时动态创建 input 兜底。

<js>

var submitLock = false;

var retryMax = 1;

var retryCount = 0;

 

function submitZlsqForm() {

    if (submitLock) return;

    submitLock = true;

    $.ajax({

        url: $('#zlsqForm').attr('action'),

        type: 'POST',

        data: $('#zlsqForm').serialize(),

        dataType: 'json',

        success: function(res){

            submitLock = false;

            // 标准token处理逻辑

            if (res.token && res.token.name && res.token.value && retryCount < retryMax) {

                retryCount++;

                var token = res.token;

                var tokenInput = $('#zlsqForm input[name="'+token.name+'"]');

                if (tokenInput.length > 0) {

                    tokenInput.val(token.value);

                } else {

                    $('<input type="hidden" name="'+token.name+'" value="'+token.value+'">').appendTo('#zlsqForm');

                }

                submitZlsqForm();

                return;

            }

            // 后续业务成功/失败判断逻辑省略

        },

        error: function(){

            submitLock = false;

            alert('网络异常,请稍后重试,不要重复点击');

        }

    });

}

 

三、第二大坑:弹窗验证码首次提交必提示错误(Session 写入延迟)

现象

打开弹窗立刻刷新验证码,无论输入内容对错,第一次提交全部提示验证码错误,手动点击刷新图片后才正常。

根因

验证码 API /index.php?s=api&c=api&m=captcha 写入 Session 存在毫秒级延迟,弹窗同步刷新时,前端图片与后端 Session 内存储验证码不一致。

修复方案

弹窗显示后延时 200ms 再加载验证码,且选择器精准限定当前表单,不干扰页面其他表单验证码:

 

<js>

function openZlsqPop(url, title) {

    zlsqDownUrl = url;

    $('#down_title').val(title);

    $('#down_zlbt').val(title);

    $('#down_file').val(url);

    $('#zlsqShade, #zlsqPop').show();

    // 延时刷新,给session写入缓冲时间

    setTimeout(function(){

        $('#zlsqForm input[name="code"]').val('');

        $('#zlsqForm .fc-code').attr('src','/index.php?s=api&c=api&m=captcha&t='+Date.now());

    },200);

}

配套规范约束

 

页面多表单共用 name="code",所有验证码操作必须限定 #表单 ID,禁止全局 $('input [name="code"]')

仅允许用户手动点击图片刷新验证码,失败、网络异常分支全部删除自动刷新代码;

验证码随机参数统一使用 Date.now (),替换 Math.random () 避免浏览器缓存旧图片。

 

四、第三大坑:自定义表单缺失 data [fileurl] 隐藏域,邮件无资料下载链接

现象

弹窗没有存放文章附件地址的 data [fileurl] 输入框,后端邮件模板读取不到下载地址,客户收到表单通知邮件无资料链接。

修复配套代码

弹窗打开时同步给 3 个邮件必填隐藏域赋值:

 

<js>

$('#down_title').val(title);

$('#down_zlbt').val(title);

$('#down_file').val(zlsqDownUrl);

 

页面表单内提前定义 3 个隐藏 input

html

<input type="hidden" name="data[title]" id="down_title">

<input type="hidden" name="data[zlbt]" id="down_zlbt">

<input type="hidden" name="data[fileurl]" id="down_file">

 

五、第四大坑:想使用原生 {form} cms.js,无可用成功回调事件

踩坑说明

很多人以为 cms.js 内置 dr_form_successdr_form_error 全局监听事件,想用原生表单规避自定义 AJAX 流量问题;实际底层 dr_ajax_submit 是内部私有逻辑,不会抛出任何全局可监听 jQuery 事件,提交成功后无法执行前端下载弹窗,功能直接作废。

两种取舍方案

纯前端不改系统源码(推荐线上):使用带锁、限 1 次重试的自定义 AJAX(上文稳定方案);

想要原生表单拓展回调:必须修改根目录 cms.js 框架核心文件,手动在成功分支 trigger 自定义事件,CMS 版本升级会覆盖源码,维护成本极高,不建议线上使用。

 

六、第五大坑:异步 AJAX window.open 自动下载,被浏览器安全策略拦截

现象

表单提交成功后异步回调里执行 window.open (下载地址),浏览器静默拦截新标签,用户看不到下载窗口,误以为提交失效。

最优替代方案

不自动新开窗口,弹窗内静态展示下载超链接,由用户手动点击,100% 规避拦截:

 

<js>

if(isSuccess){

    alert('提交成功!下方链接可下载资料');

    $('#downloadTip').html('下载链接:<a target="_blank" href="'+zlsqDownUrl+'">点击下载</a>').show();

}

 

七、第六大坑:拉高弹窗 z-index 后点击输入框跳转到联系我们页面

根因

原版弹窗层级极低,点击会穿透到底层空白,不会触发页面全局 document 跳转监听;优化时加高遮罩层级,但未全局阻断冒泡,弹窗内点击事件冒泡到 document,触发页面跳转。

规避方案

保留原始低层级弹窗 DOM 结构,不新增高 z-index 遮罩、不批量添加冒泡阻断代码,彻底杜绝跳转衍生 bug

 

八、线上最终稳定纯前端方案总结(不修改系统核心源码)

表单提交:手写受控 AJAX,放弃无回调原生 {form}

Token 防护:正确读取 res.token 子对象,submitLock 提交锁 + 最多 1 token 重试双重防刷,杜绝无限 POST

验证码规范:弹窗延时 200ms 加载、仅手动刷新、操作限定当前表单、Date.now () 防缓存;

下载交互:弹窗内展示手动点击链接,禁止异步自动 window.open

弹窗布局:沿用原版低层级 DOM,不新增遮罩、不批量阻断冒泡,避免跳转;

邮件字段:完整保留 data [title]/data [zlbt]/data [fileurl] 三个隐藏域,邮件正常携带资料下载地址。