You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

未验证hCAPTCHA时阻止表单页面刷新的技术问题

解决hCAPTCHA未验证时表单刷新的问题

当前表单采用传统同步提交模式,无论验证结果如何都会触发页面刷新,导致未完成hCAPTCHA时也会回到页面顶部,体验不佳。要实现未验证时阻止刷新,需要结合前端JavaScript拦截提交事件,先完成hCAPTCHA验证,再通过AJAX异步提交表单。以下是具体修改方案:

一、前端HTML/JS修改

首先确保引入hCAPTCHA官方脚本,然后添加表单提交拦截逻辑,阻止默认刷新行为:

<form method="post" id="contactform" name="contactform" action="/contact">
    <!-- 原表单所有字段保持不变 -->
    
    <div class="h-captcha" name="h-captcha" id="hcaptcha" data-sitekey="你的sitekey"></div>
    
    <?php if(!empty($errMsg)): ?><div class="errMsg" id="errMsg"><?php echo $errMsg; ?></div><?php endif; ?>
    <?php if(!empty($succMsg)): ?><div class="succMsg"><?php echo $succMsg; ?></div><?php endif; ?>
    
    <div class="bot-cont"><button type="submit" name="submit" class="submit_button" value="Submit">SUBMIT MESSAGE</button></div>
    <br/><br/>
    <label>* required fields</label>            
</form>

<!-- 引入hCAPTCHA脚本 -->
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
<script>
document.getElementById('contactform').addEventListener('submit', function(e) {
    // 阻止默认表单提交刷新
    e.preventDefault();
    
    // 验证hCAPTCHA是否完成
    const captchaResponse = document.querySelector('[name="h-captcha-response"]');
    if (!captchaResponse || captchaResponse.value === '') {
        const errEl = document.getElementById('errMsg');
        errEl.textContent = '请完成CAPTCHA验证';
        errEl.style.display = 'block';
        // 滚动到错误提示位置
        errEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
        return;
    }
    
    // 验证HTML5原生必填字段
    if (!this.checkValidity()) {
        this.reportValidity();
        return;
    }
    
    // 异步提交表单
    const formData = new FormData(this);
    fetch(this.action, {
        method: 'POST',
        body: formData
    })
    .then(res => res.json())
    .then(data => {
        if (data.success) {
            // 提交成功跳转感谢页
            window.location.href = data.redirectUrl;
        } else {
            const errEl = document.getElementById('errMsg');
            errEl.textContent = data.message;
            errEl.style.display = 'block';
            errEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
            // 重置hCAPTCHA
            hcaptcha.reset();
        }
    })
    .catch(() => {
        const errEl = document.getElementById('errMsg');
        errEl.textContent = '提交失败,请稍后重试';
        errEl.style.display = 'block';
        hcaptcha.reset();
    });
});
</script>

二、后端PHP代码修改

调整后端逻辑,返回JSON格式响应,适配AJAX请求:

<?php
session_start();

// hCAPTCHA密钥配置
$secretKey = '你的secretKey';

// 存储用户选择到session
$_SESSION['terms'] = !empty($_POST['terms']);
$_SESSION['newsletter'] = !empty($_POST['newsletter']);

$email_exp = '/^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/';
$string_exp = "/^[A-Za-z .'-]+$/";

// 初始化响应数据
$response = ['success' => false, 'message' => '', 'redirectUrl' => ''];

if(isset($_POST['submit'])){ 
    // 验证必填字段
    if(empty($_POST['name']) || empty($_POST['email']) || empty($_POST['message'])){
        $response['message'] = '请填写所有必填字段';
    } elseif(empty($_POST['h-captcha-response'])){
        $response['message'] = '请完成CAPTCHA验证';
    } else {
        // 验证hCAPTCHA
        $verifyURL = 'https://hcaptcha.com/siteverify';
        $token = $_POST['h-captcha-response'];
        $data = [
            'secret' => $secretKey,
            'response' => $token,
            'remoteip' => $_SERVER['REMOTE_ADDR']
        ];
        
        $curlConfig = [
            CURLOPT_URL => $verifyURL,
            CURLOPT_POST => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POSTFIELDS => $data
        ];
        $ch = curl_init();
        curl_setopt_array($ch, $curlConfig);
        $captchaRes = curl_exec($ch);
        curl_close($ch);
        
        $captchaData = json_decode($captchaRes);
        if($captchaData->success){
            // 处理邮件发送
            $email_to = "你的邮箱地址";
            $email_subject = "表单提交通知";
            $ip_address = $_SERVER['REMOTE_ADDR'];
            $geopluginURL = 'http://www.geoplugin.net/php.gp?ip='.$ip_address;
            $addrDetails = unserialize(file_get_contents($geopluginURL));
            $country = $addrDetails['geoplugin_countryName'];
            
            $name = $_POST['name'];
            $where = $_POST['where'];
            $email_from = $_POST['email'];
            $message = $_POST['message'];
            $newsletter = isset($_POST['newsletter']) ? '是' : '否';
            $terms = isset($_POST['terms']) ? '同意' : '不同意';
            
            function clean_string($string) {
                $bad = array("content-type","bcc:","to:","cc:","href");
                return str_replace($bad,"",$string);
            }
            
            $email_content = "表单详情如下:<br/><br/><br/>";
            $email_content .= "IP: ".clean_string($ip_address)."<br/><br/>";
            $email_content .= "国家: ".clean_string($country)."<br/><br/><br/>";
            $email_content .= "姓名: ".clean_string($name)."<br/><br/>";
            $email_content .= "获知渠道: ".clean_string($where)."<br/><br/>";
            $email_content .= "邮箱: ".clean_string($email_from)."<br/><br/>";
            $email_content .= "订阅新闻: ".clean_string($newsletter)."<br/><br/>";
            $email_content .= "留言: ".clean_string($message)."<br/><br/>";
            
            $headers = "MIME-Version: 1.0" . "\r\n";
            $headers .= "Content-type:text/html;charset=UTF-8" . "\r\n";
            $headers .= 'From:'.$name.' <'.$email_from.'>' . "\r\n";
            
            // 发送邮件
            @mail($email_to, $email_subject, $email_content, $headers);
            
            // 设置成功响应
            $response['success'] = true;
            $response['redirectUrl'] = $site_url.'/thank-you';
        } else {
            $response['message'] = '验证失败,请重试';
        }
    }
}

// 返回JSON响应
header('Content-Type: application/json');
echo json_encode($response);
exit;
?>

三、额外代码修复点

  1. 原HTML中terms复选框的PHP代码存在语法错误,修改为:
<input name="terms" type="checkbox" <?php echo (!empty($_SESSION['terms']) && $_SESSION['terms'] == true) ? 'checked="checked"' : ''; ?>
       oninvalid="this.setCustomValidity('Please indicate that you have read and accept our Terms of Use and Privacy Policy agreements.')"
       oninput="setCustomValidity('')" required>
  1. 原PHP中重复调用session_start(),保留开头一次即可;修复邮件发送时From头未定义的变量问题。

内容的提问来源于stack exchange,提问作者will

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 22:05:53