【问题标题】:How to get recaptcha token in SvelteKit contact form如何在 SvelteKit 联系表中获取 recaptcha 令牌
【发布时间】:2021-10-22 04:45:24
【问题描述】:

我正在使用 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 令牌除外。

感谢任何关于如何解决它的想法。

【问题讨论】:

    标签: javascript recaptcha sveltekit


    【解决方案1】:

    token 为 null,因为您的 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 函数并让它们运行,只是不能保证函数中的内容会在调用之后的代码之前运行。

    【讨论】:

    • 感谢您的广泛回复。我将首先阅读您建议的帖子并尝试您的解决方案。我很快回来。干杯
    【解决方案2】:

    为了澄清,我的最终代码在提交功能中略有不同,我将其发布以供将来参考,以防万一。

    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;
            }
        }

    【讨论】:

      【解决方案3】:

      您可以使用svelte-recaptcha-v2,而不是自己处理。

      存储库

      https://github.com/basaran/svelte-recaptcha-v2

      演示

      https://basaran.github.io/svelte-recaptcha-v2/demo

      P。 S 我是包的作者。

      【讨论】:

      • 感谢您的意见。我相信它对我们很多人都有用。在这种情况下,In 使用 recaptcha v3 上接受的答案解决了它。但我会为您的包裹添加书签以备将来使用。
      猜你喜欢
      • 1970-01-01
      • 2021-09-15
      • 2018-12-31
      • 1970-01-01
      • 2016-07-16
      • 1970-01-01
      • 1970-01-01
      • 2021-09-15
      • 1970-01-01
      相关资源
      最近更新 更多