如何在 SvelteKit 联系表单中获取 recaptcha 令牌
How to get recaptcha token in SvelteKit contact form
我正在使用 SvelteKit 开发一个静态网站来获得我的第一个 svelte 方法。我几乎让一切都按预期工作。
除了联系人表单上的重新验证保护之外的所有内容。
我可以获得 recaptcha 令牌,但在将它传递给 formData 请求时我丢失了它。
我的相关代码是:
<script lang="ts">
import * as yup from "yup";
import {createForm, ErrorMessage} from "svelte-forms-lib";
...
function getCaptcha(){
grecaptcha.ready(function () {
grecaptcha.execute('recaptcha-key', { action: 'contactForm' })
.then(function (token) {
console.log(token) // here I get the token
return token;
});
});
}
const sendMail= (values)=>
{
const url = '/sendmail.php';
const formData = new FormData();
let token = getCaptcha();
console.log('token: '+token); // here token is null
formData.append("token", token);
fetch(url, {
method: 'post',
body: formData,
})
.then(function (response) {
console.debug(response.status)
})
.catch(function (e) {
sendError = true;
console.debug(e);
});
}
</script>
表单提交工作正常,除了 recaptcha 令牌。
感谢您提供解决方法。
token
为空,因为您的 getCaptcha
函数实际上并未返回任何内容,因为您正在使用回调来获取令牌。
function getCaptcha(){ // <- this function isn't returning anything
grecaptcha.ready(function () {
grecaptcha.execute('recaptcha-key', { action: 'contactForm' })
.then(function (token) { // <- this function returns, but the value isn't going anywhere
console.log(token);
return token;
});
});
}
要解决此问题,您可能需要研究使用 async
/await
语法来实现承诺。 MDN has a great article如果你有兴趣。
你可能想做这样的事情:
async function getCaptcha(){
await new Promise((resolve, reject) => {
// grecaptcha.ready needs a callback so we create a promise to await
grecaptcha.ready(resolve);
});
// grecaptcha.execute returns a promise so we can await it
const token = await grecaptcha.execute('recaptcha-key', { action: 'contactForm' });
console.log(token);
return token;
}
const sendMail = async (values) => {
const url = '/sendmail.php';
const formData = new FormData();
let token = await getCaptcha();
console.log('token: ' + token);
formData.append("token", token);
// you have a few options for converting
// the Promise.catch()
// you can use a try {} catch {} block
// or you can use .catch() on this sendMail function
try {
const response = fetch(url, {
method: 'post',
body: formData,
});
console.debug(response.status);
} catch (e) {
sendError = true;
console.debug(e);
}
}
请记住,这将使 sendMail
函数成为 async
函数,这意味着您将不得不 await
调用它,或使用 sendMail().then()
。我相信也可以直接在同步代码中调用 async
函数并让它们 运行,只是不能保证函数中的内容会 运行 在调用后的代码之前.
为了澄清起见,我的最终代码在提交功能上略有不同,我将其发布以供将来参考,以防万一。
async function getCaptcha(){
await new Promise((resolve, reject) => {
// grecaptcha.ready needs a callback so we create a promise to await
grecaptcha.ready(resolve);
});
// grecaptcha.execute returns a promise so we can await it
const token = await grecaptcha.execute('site-key', { action: 'contactForm' });
return token;
}
const sendMail = async (values) => {
const url = '/sendmail.php';
const formData = new FormData();
let token = await getCaptcha();
formData.append("name", values.name);
formData.append("surname", values.surname);
formData.append("email", values.email);
formData.append("phone", values.phone);
formData.append("message", values.message);
formData.append("token", token);
formData.append("action", "contactForm");
// you have a few options for converting
// the Promise.catch()
// you can use a try {} catch {} block
// or you can use .catch() on this sendMail function
try {
let response = await fetch(url, {
method: 'post',
body: formData,
});
if(response.status == 202){
sendSuccess = true;
document.querySelector('form').reset();
}
if(response.status == 400){
sendError = true;
}
} catch(err) {
sendError = true;
}
}
您可以使用 svelte-recaptcha-v2
.
而不是自己处理
存储库
https://github.com/basaran/svelte-recaptcha-v2
演示
https://basaran.github.io/svelte-recaptcha-v2/demo
P. S 我是包的作者。
我正在使用 SvelteKit 开发一个静态网站来获得我的第一个 svelte 方法。我几乎让一切都按预期工作。 除了联系人表单上的重新验证保护之外的所有内容。
我可以获得 recaptcha 令牌,但在将它传递给 formData 请求时我丢失了它。 我的相关代码是:
<script lang="ts">
import * as yup from "yup";
import {createForm, ErrorMessage} from "svelte-forms-lib";
...
function getCaptcha(){
grecaptcha.ready(function () {
grecaptcha.execute('recaptcha-key', { action: 'contactForm' })
.then(function (token) {
console.log(token) // here I get the token
return token;
});
});
}
const sendMail= (values)=>
{
const url = '/sendmail.php';
const formData = new FormData();
let token = getCaptcha();
console.log('token: '+token); // here token is null
formData.append("token", token);
fetch(url, {
method: 'post',
body: formData,
})
.then(function (response) {
console.debug(response.status)
})
.catch(function (e) {
sendError = true;
console.debug(e);
});
}
</script>
表单提交工作正常,除了 recaptcha 令牌。
感谢您提供解决方法。
token
为空,因为您的 getCaptcha
函数实际上并未返回任何内容,因为您正在使用回调来获取令牌。
function getCaptcha(){ // <- this function isn't returning anything
grecaptcha.ready(function () {
grecaptcha.execute('recaptcha-key', { action: 'contactForm' })
.then(function (token) { // <- this function returns, but the value isn't going anywhere
console.log(token);
return token;
});
});
}
要解决此问题,您可能需要研究使用 async
/await
语法来实现承诺。 MDN has a great article如果你有兴趣。
你可能想做这样的事情:
async function getCaptcha(){
await new Promise((resolve, reject) => {
// grecaptcha.ready needs a callback so we create a promise to await
grecaptcha.ready(resolve);
});
// grecaptcha.execute returns a promise so we can await it
const token = await grecaptcha.execute('recaptcha-key', { action: 'contactForm' });
console.log(token);
return token;
}
const sendMail = async (values) => {
const url = '/sendmail.php';
const formData = new FormData();
let token = await getCaptcha();
console.log('token: ' + token);
formData.append("token", token);
// you have a few options for converting
// the Promise.catch()
// you can use a try {} catch {} block
// or you can use .catch() on this sendMail function
try {
const response = fetch(url, {
method: 'post',
body: formData,
});
console.debug(response.status);
} catch (e) {
sendError = true;
console.debug(e);
}
}
请记住,这将使 sendMail
函数成为 async
函数,这意味着您将不得不 await
调用它,或使用 sendMail().then()
。我相信也可以直接在同步代码中调用 async
函数并让它们 运行,只是不能保证函数中的内容会 运行 在调用后的代码之前.
为了澄清起见,我的最终代码在提交功能上略有不同,我将其发布以供将来参考,以防万一。
async function getCaptcha(){
await new Promise((resolve, reject) => {
// grecaptcha.ready needs a callback so we create a promise to await
grecaptcha.ready(resolve);
});
// grecaptcha.execute returns a promise so we can await it
const token = await grecaptcha.execute('site-key', { action: 'contactForm' });
return token;
}
const sendMail = async (values) => {
const url = '/sendmail.php';
const formData = new FormData();
let token = await getCaptcha();
formData.append("name", values.name);
formData.append("surname", values.surname);
formData.append("email", values.email);
formData.append("phone", values.phone);
formData.append("message", values.message);
formData.append("token", token);
formData.append("action", "contactForm");
// you have a few options for converting
// the Promise.catch()
// you can use a try {} catch {} block
// or you can use .catch() on this sendMail function
try {
let response = await fetch(url, {
method: 'post',
body: formData,
});
if(response.status == 202){
sendSuccess = true;
document.querySelector('form').reset();
}
if(response.status == 400){
sendError = true;
}
} catch(err) {
sendError = true;
}
}
您可以使用 svelte-recaptcha-v2
.
存储库
https://github.com/basaran/svelte-recaptcha-v2
演示
https://basaran.github.io/svelte-recaptcha-v2/demo
P. S 我是包的作者。