如何同步等待 reCAPTCHA v3 令牌?
How to wait for the reCAPTCHA v3 token synchronously?
I'm in a bind, and Javascript world it's very weird.
在继续提交表单之前,我需要使用 reCAPTCHA v3 令牌 resolved 创建一个表单。由于某些事件绑定到表单 submit
事件,事件循环必须等到它被解决否则失败:
- 某些表单具有验证事件,如果出现错误(例如输入中的无效值),会阻止提交。
- 如果用户在页面加载时点击表单的速度太快(由于自动完成),并且仍未检索到令牌,则请求 returns 出错。
虽然我正在尝试做的是让 submit
事件的侦听器 阻止提交,直到令牌被解析 然后再继续与其他侦听器.
目前关于 reCAPTCHA 脚本的文档为零,我还没有找到可靠的方法来实际和强制解析令牌。 reCAPTCHA 脚本是异步的,所以没有办法等到令牌被解析:
// Let's retrieve the form by its id.
let form = document.getElementById('example_form');
let addToken = (form) => {
grecaptcha.execute('site_key', {
// some options
}).then(token => {
// Include the token as an input inside the form so it's sent.
});
};
form.addEventListener('submit', () => {
return addToken(form); // <-- This won't work, since it's async.
});
您可以在加载令牌之前禁用表单提交,而是显示一些加载程序。在 then
回调中,您将令牌保存在表单字段中并启用表单提交(并隐藏加载程序)。
如果你想让它更无缝,你可以向用户隐藏这个过程:如果用户在加载令牌之前提交表单,然后你禁用按钮(并阻止常规提交尝试)并改为显示加载程序并记住提交正在等待,当稍后收到令牌时,您检查提交是否正在等待,如果是,您以编程方式提交表单(包括令牌) .
这样用户就不会遇到加载程序,除非他们实际上过早地提交了表单。
想通了,没办法让recaptcha.execute()
同步。换句话说,等待令牌从服务器解析是不可能的。
相反,您应该通过请求初始令牌来漫不经心地敲打 reCAPTCHA 服务器,然后通过 100 秒的间隔设置相同的操作以确保在过期前收到令牌。
此代码针对多种形式进行了调整。使用风险自负。
const site_key = 'HEREYOURSITEKEY';
// This function retrieves the token from reCAPTCHA.
const retrieveToken = (form) => {
// Mark the form as unresolved until the retrieval ends.
form.unresolved = true;
// Get the token.
grecaptcha.execute(site_key, {
action: form.action.substring(action.indexOf('?'), action.length).replace(/[^A-z\/_]/gi, '')
}).then(token => {
// Append the token to the form so it's sent along the other data.
let child = document.createElement('input');
child.setAttribute('type', 'hidden');
child.setAttribute('name', '_recaptcha');
child.setAttribute('value', token);
form.appendChild(child);
form.unresolved = false;
});
};
// We will loop for each form in the document. You can add a "filter" method if you want.
Array.from(document.getElementByTagName('form'))
.forEach(form => {
// Mark it as unresolved from the beginning.
form.unresolved = true;
// Add an event listener that disables submission if the form is unresolved.
form.addEventListener('submit', event => {
if (form.unresolved) {
event.preventDefault();
}
});
// Resolve the token at startup.
retrieveToken(form);
// And retrieve a new token each 100 seconds. Bite me.
setInterval(() => refreshToken(form), 100 * 1000);
});
我遇到了同样的问题。这是我的解决方案:
async function recaptchaCall(){
var recaptcha_token = '';
grecaptcha.ready(() => {
grecaptcha.execute(grecaptchaKey, {action: 'submit'}).then((token) => {
recaptcha_token = token;
});
});
while(recaptcha_token == ''){
await new Promise(r => setTimeout(r, 100));
}
return recaptcha_token;
}
let recaptcha_token = await recaptchaCall();
我认为这是最好的解决方案,因为不可能使其作为同步功能正确运行。我正在使用 setTimeout 等待收到 Recaptcha 答复。希望对你有帮助。
JavaScript 无法等待重新验证请求完成。
我使用一个时间戳全局变量来完成这项工作,我在每次提交时将该变量与当前时间戳进行比较。因此,onSubmit 有两种行为:如果需要请求新令牌,则 onSubmit 仅处理 recaptcha 令牌(阻止提交)。如果没有必要,那么它会执行通常的操作(验证和其他内容)。
<script src="https://www.google.com/recaptcha/api.js?render=SITE_KEY"></script>
<script>
$(function() {
// last recaptcha token timestamp in ms (to check if the refresh interval of max 2 minutes is reached in between submit attempts)
recaptchaLoginLastTokenTimestamp = 0;
$("#loginform").on('submit', function(e){
nowTimestamp = new Date().getTime();
// if 100 seconds passed since last recaptcha token => get new token
if(nowTimestamp - recaptchaLoginLastTokenTimestamp > 100000){
// stop submission
e.preventDefault();
// call the recaptcha service to get a token
grecaptcha.ready(function() {
grecaptcha.execute('SITE_KEY', {action:'action_login'})
.then(function(token)
{
// add token value to form
document.getElementById('recaptcha_response_token').value = token;
// update last token timestamp
recaptchaLoginLastTokenTimestamp = new Date().getTime();
// re-submit (with the updated token timestamp, the normal submit process will occur, with validations and other stuff that are bind to submission; no infinite recursive submit calls)
$("#loginform").submit();
});
});
}
});
});
</script>
I'm in a bind, and Javascript world it's very weird.
在继续提交表单之前,我需要使用 reCAPTCHA v3 令牌 resolved 创建一个表单。由于某些事件绑定到表单 submit
事件,事件循环必须等到它被解决否则失败:
- 某些表单具有验证事件,如果出现错误(例如输入中的无效值),会阻止提交。
- 如果用户在页面加载时点击表单的速度太快(由于自动完成),并且仍未检索到令牌,则请求 returns 出错。
虽然我正在尝试做的是让 submit
事件的侦听器 阻止提交,直到令牌被解析 然后再继续与其他侦听器.
目前关于 reCAPTCHA 脚本的文档为零,我还没有找到可靠的方法来实际和强制解析令牌。 reCAPTCHA 脚本是异步的,所以没有办法等到令牌被解析:
// Let's retrieve the form by its id.
let form = document.getElementById('example_form');
let addToken = (form) => {
grecaptcha.execute('site_key', {
// some options
}).then(token => {
// Include the token as an input inside the form so it's sent.
});
};
form.addEventListener('submit', () => {
return addToken(form); // <-- This won't work, since it's async.
});
您可以在加载令牌之前禁用表单提交,而是显示一些加载程序。在 then
回调中,您将令牌保存在表单字段中并启用表单提交(并隐藏加载程序)。
如果你想让它更无缝,你可以向用户隐藏这个过程:如果用户在加载令牌之前提交表单,然后你禁用按钮(并阻止常规提交尝试)并改为显示加载程序并记住提交正在等待,当稍后收到令牌时,您检查提交是否正在等待,如果是,您以编程方式提交表单(包括令牌) .
这样用户就不会遇到加载程序,除非他们实际上过早地提交了表单。
想通了,没办法让recaptcha.execute()
同步。换句话说,等待令牌从服务器解析是不可能的。
相反,您应该通过请求初始令牌来漫不经心地敲打 reCAPTCHA 服务器,然后通过 100 秒的间隔设置相同的操作以确保在过期前收到令牌。
此代码针对多种形式进行了调整。使用风险自负。
const site_key = 'HEREYOURSITEKEY';
// This function retrieves the token from reCAPTCHA.
const retrieveToken = (form) => {
// Mark the form as unresolved until the retrieval ends.
form.unresolved = true;
// Get the token.
grecaptcha.execute(site_key, {
action: form.action.substring(action.indexOf('?'), action.length).replace(/[^A-z\/_]/gi, '')
}).then(token => {
// Append the token to the form so it's sent along the other data.
let child = document.createElement('input');
child.setAttribute('type', 'hidden');
child.setAttribute('name', '_recaptcha');
child.setAttribute('value', token);
form.appendChild(child);
form.unresolved = false;
});
};
// We will loop for each form in the document. You can add a "filter" method if you want.
Array.from(document.getElementByTagName('form'))
.forEach(form => {
// Mark it as unresolved from the beginning.
form.unresolved = true;
// Add an event listener that disables submission if the form is unresolved.
form.addEventListener('submit', event => {
if (form.unresolved) {
event.preventDefault();
}
});
// Resolve the token at startup.
retrieveToken(form);
// And retrieve a new token each 100 seconds. Bite me.
setInterval(() => refreshToken(form), 100 * 1000);
});
我遇到了同样的问题。这是我的解决方案:
async function recaptchaCall(){
var recaptcha_token = '';
grecaptcha.ready(() => {
grecaptcha.execute(grecaptchaKey, {action: 'submit'}).then((token) => {
recaptcha_token = token;
});
});
while(recaptcha_token == ''){
await new Promise(r => setTimeout(r, 100));
}
return recaptcha_token;
}
let recaptcha_token = await recaptchaCall();
我认为这是最好的解决方案,因为不可能使其作为同步功能正确运行。我正在使用 setTimeout 等待收到 Recaptcha 答复。希望对你有帮助。
JavaScript 无法等待重新验证请求完成。 我使用一个时间戳全局变量来完成这项工作,我在每次提交时将该变量与当前时间戳进行比较。因此,onSubmit 有两种行为:如果需要请求新令牌,则 onSubmit 仅处理 recaptcha 令牌(阻止提交)。如果没有必要,那么它会执行通常的操作(验证和其他内容)。
<script src="https://www.google.com/recaptcha/api.js?render=SITE_KEY"></script>
<script>
$(function() {
// last recaptcha token timestamp in ms (to check if the refresh interval of max 2 minutes is reached in between submit attempts)
recaptchaLoginLastTokenTimestamp = 0;
$("#loginform").on('submit', function(e){
nowTimestamp = new Date().getTime();
// if 100 seconds passed since last recaptcha token => get new token
if(nowTimestamp - recaptchaLoginLastTokenTimestamp > 100000){
// stop submission
e.preventDefault();
// call the recaptcha service to get a token
grecaptcha.ready(function() {
grecaptcha.execute('SITE_KEY', {action:'action_login'})
.then(function(token)
{
// add token value to form
document.getElementById('recaptcha_response_token').value = token;
// update last token timestamp
recaptchaLoginLastTokenTimestamp = new Date().getTime();
// re-submit (with the updated token timestamp, the normal submit process will occur, with validations and other stuff that are bind to submission; no infinite recursive submit calls)
$("#loginform").submit();
});
});
}
});
});
</script>