未验证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; ?>
三、额外代码修复点
- 原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>
- 原PHP中重复调用
session_start(),保留开头一次即可;修复邮件发送时From头未定义的变量问题。
内容的提问来源于stack exchange,提问作者will
相关产品推荐
相关产品推荐

