如何正确地将电子邮件和姓名传递给Stripe中创建的客户?

huangapple go评论94阅读模式
英文:

How to correctly pass email and name to created customers in Stripe?

问题

以下是您的代码的翻译:

服务器端(Node.js):

app.post("/create-payment-intent", async (req, res) => {
    const { email, name } = req.body;
    const customer = await stripe.customers.create({ email, name });
    const paymentIntent = await stripe.paymentIntents.create({
      customer: customer.id,
      setup_future_usage: "off_session",
      amount: 2499,
      currency: "usd",
      automatic_payment_methods: { enabled: true }
    });
    res.send({ clientSecret: paymentIntent.client_secret });
});

客户端:

<body>
    <form id="payment-form">
        <input type="email" id="email" placeholder="输入电子邮件地址" required/>
        <input type="text" id="name" placeholder="全名" required/>
        <div id="payment-element"></div>
        <button class="str" id="submit">
            <div class="spinner hidden" id="spinner"></div>
            <span id="button-text">提交</span>
        </button>
        <div id="payment-message" class="hidden"></div>
    </form>

    <script>
        document.addEventListener('DOMContentLoaded', async () => {
            const { publicKey, endPoint } = await fetch('/config').then((r) => r.json())
            const stripe = Stripe(publicKey)
            const endpoint = endPoint

            const email = document.getElementById('email').value;
            const name = document.getElementById('name').value;

            const response = await fetch("/create-payment-intent", {
                method: "POST",
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ email, name })
            })
            const { clientSecret } = await response.json();

            const appearance = { theme: 'flat' };
            const elements = stripe.elements({ clientSecret, appearance });
            const paymentElement = elements.create('payment')
            paymentElement.mount('#payment-element')

            const form = document.getElementById("payment-form")
            form.addEventListener('submit', async (e) => {
                e.preventDefault();
                setLoading(true);

                const { error } = await stripe.confirmPayment({
                    elements,
                    confirmParams: {
                        return_url: endpoint
                    }
                })
                if (error) {
                    const message = document.getElementById("payment-message")
                    message.innerText = error.message;
                }

                setLoading(false);
            })
        })
    </script>
</body>

7.17.23 更新:

好的,我终于成功了,但是只有在 DOM 加载之前填写了电子邮件和姓名字段才有效(就像我输入了我的电子邮件和姓名,重新加载页面,我的数据仍然填写)。因此,我尝试将电子邮件和姓名移到提交事件内部,但它没有起作用。问题仍然是一样的 - 如何将电子邮件和姓名传递给已创建的客户,但是我猜测我需要在提交事件内传递它,它应该更新客户(因为当表单加载时,它已经从这些字段传递数据了)?

英文:

My current code is:
server (Node js)

app.post(&quot;/create-payment-intent&quot;, async (req, res) =&gt; {
const { email, name } = req.body;
const customer = await stripe.customers.create({ email, name });
const paymentIntent = await stripe.paymentIntents.create({
customer: customer.id,
setup_future_usage: &quot;off_session&quot;,
amount: 2499,
currency: &quot;usd&quot;,
automatic_payment_methods: { enabled: true }
});
res.send({ clientSecret: paymentIntent.client_secret });
});

client

&lt;body&gt;
&lt;form id=&quot;payment-form&quot;&gt;
&lt;input type=&quot;email&quot; id=&quot;email&quot; placeholder=&quot;Enter email address&quot; required/&gt;
&lt;input type=&quot;text&quot; id=&quot;name&quot; placeholder=&quot;Full Name&quot; required/&gt;
&lt;div id=&quot;payment-element&quot;&gt;&lt;/div&gt;
&lt;button class=&quot;str&quot; id=&quot;submit&quot;&gt;
&lt;div class=&quot;spinner hidden&quot; id=&quot;spinner&quot;&gt;&lt;/div&gt;
&lt;span id=&quot;button-text&quot;&gt;Submit&lt;/span&gt;
&lt;/button&gt;
&lt;div id=&quot;payment-message&quot; class=&quot;hidden&quot;&gt;&lt;/div&gt;
&lt;/form&gt;
&lt;script&gt;
document.addEventListener(&#39;DOMContentLoaded&#39;, async () =&gt; {
const {publicKey, endPoint} = await fetch(&#39;/config&#39;).then((r) =&gt; r.json())
const stripe = Stripe(publicKey)
const endpoint = (endPoint)
const email = document.getElementById(&#39;email&#39;).value;
const name = document.getElementById(&#39;name&#39;).value;
const response = await fetch(&quot;/create-payment-intent&quot;, {
method: &quot;POST&quot;,
headers: {
&#39;Content-Type&#39;: &#39;application/json&#39;
},
body: JSON.stringify({email, name})
})
const { clientSecret } = await response.json();
const appearance = { theme: &#39;flat&#39; };
const elements = stripe.elements({ clientSecret, appearance });
const paymentElement = elements.create(&#39;payment&#39;)
paymentElement.mount(&#39;#payment-element&#39;)
const form = document.getElementById(&quot;payment-form&quot;)
form.addEventListener(&#39;submit&#39;, async (e) =&gt; {
e.preventDefault();
setLoading(true);
const {error} = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: (endpoint)
}
})
if(error) {
const message = document.getElementById(&quot;payment-message&quot;)
message.innerText = error.message;
}
setLoading(false);
})
})
&lt;/script&gt;
&lt;/body&gt;

7.17.23 UPDATE:

Well, I finally did it BUT - it only works if email and name fields are already filled before DOM loads (like I enter my email and name, reload page and my data still filled). So I tried to move the email and name inside the submit but it didn't work. Question is the same - how to pass email and name to already created customer but as I may guess I need to pass it inside the submit event and it should update the customer (because when form is loaded it already passes data from these fields)?

答案1

得分: 1

我认为你只是有点混淆了你的条带方法顺序。在大多数情况下,您可以按照以下顺序操作:

  1. 创建一个客户
  2. 为您的客户创建付款
  3. 确认您刚刚为客户创建的付款

因此,您的服务器代码应该类似于这样:

app.post("/create-payment-intent", async (req, res) => {
  const { email, name } = req.body;

  // 步骤 1)创建客户
  const customer = await stripe.customers.create({
    email: email,
    name: name,
  });

  // 步骤 2)为您的客户创建付款
  const paymentIntent = await stripe.paymentIntents.create({
    customer: customer.id,
    setup_future_usage: "off_session",
    amount: 2499,
    currency: "usd",
    automatic_payment_methods: { enabled: true },
  });

  // 将 client_secret 发送到前端以便我们可以确认付款
  res.send({ clientSecret: paymentIntent.client_secret });
});

而您的前端代码应该类似于这样:

<form id="payment-form">
  ...
  <button class="str" id="submit">提交</button>
  ...
</form>

<script>
  document.addEventListener('DOMContentLoaded', async () => {
      ...
      const form = document.getElementById("payment-form")
      form.addEventListener('submit', async (e) => {
          e.preventDefault();

          const email = document.getElementById("email").value;
          const name = document.getElementById("name").value;

          const response = await fetch("/create-payment-intent", {
              method: "POST",
              headers: {
                  'Content-Type': 'application/json'
              },
              body: JSON.stringify({ email: email, name: name })
          })

          const { clientSecret } = await response.json()


          // 步骤 3)确认您刚刚为客户创建的付款
          const { error } = await stripe.confirmPayment({
              elements,
              confirmParams: {
                  client_secret: clientSecret, // <--- 这是您从服务器获得的客户机密
                  return_url: (endpoint)
              }
          })

          if(error) {
              const message = document.getElementById("payment-message")
              message.innerText = error.message;
          }
      })
  })
</script>
英文:

I think you just have your stripe method order a bit mixed up is all. In most cases you can follow this order:

  1. Create a customer
  2. Create a payment for your customer
  3. Confirm the payment that you just made for your customer

So you server code would look something like this:

app.post(&quot;/create-payment-intent&quot;, async (req, res) =&gt; {
  const { email, name } = req.body;

  // Step 1) Create a customer
  const customer = await stripe.customers.create({
    email: email,
    name: name,
  });

  // Step 2) Create a payment for your customer
  const paymentIntent = await stripe.paymentIntents.create({
    customer: customer.id,
    setup_future_usage: &quot;off_session&quot;,
    amount: 2499,
    currency: &quot;usd&quot;,
    automatic_payment_methods: { enabled: true },
  });

  // Send the client_secret to the frontend so we can confirm the payment
  res.send({ clientSecret: paymentIntent.client_secret });
});

And your frontend code would look something like this:

&lt;form id=&quot;payment-form&quot;&gt;
  ...
  &lt;button class=&quot;str&quot; id=&quot;submit&quot;&gt;Submit&lt;/button&gt;
  ...
&lt;/form&gt;

&lt;script&gt;
  document.addEventListener(&#39;DOMContentLoaded&#39;, async () =&gt; {
      ...
      const form = document.getElementById(&quot;payment-form&quot;)
      form.addEventListener(&#39;submit&#39;, async (e) =&gt; {
          e.preventDefault();

          const email = document.getElementById(&quot;email&quot;).value;
          const name = document.getElementById(&quot;name&quot;).value;

          const response = await fetch(&quot;/create-payment-intent&quot;, {
              method: &quot;POST&quot;,
              headers: {
                  &#39;Content-Type&#39;: &#39;application/json&#39;
              },
              body: JSON.stringify({ email: email, name: name })
          })

          const { clientSecret } = await response.json()


          // Step 3) Confirm the payment that you just made for your customer
          const { error } = await stripe.confirmPayment({
              elements,
              confirmParams: {
                  client_secret: clientSecret, // &lt;--- This is the client secret that you got from the server
                  return_url: (endpoint)
              }
          })

          if(error) {
              const message = document.getElementById(&quot;payment-message&quot;)
              message.innerText = error.message;
          }
      })
  })
&lt;/script&gt;

答案2

得分: 0

根据您的描述和您分享的代码,看起来emailname变量是在DOMContentLoaded事件发生时被赋值的。这意味着输入字段的值会在文档完全加载后立即获取,这解释了为什么需要预填字段才能使代码正常工作。

相反,您希望在表单提交时获取输入字段的值,也就是在submit事件处理程序内部获取。

尝试将这些行移动到submit事件处理程序内,如下所示:

const email = document.getElementById('email').value;
const name = document.getElementById('name').value;

submit事件处理程序内部,像这样:

document.addEventListener('DOMContentLoaded', async () => {
    const { publicKey, endPoint } = await fetch('/config').then((r) => r.json())
    const stripe = Stripe(publicKey)
    const endpoint = (endPoint)

    const form = document.getElementById("payment-form")
    form.addEventListener('submit', async (e) => {
        e.preventDefault();

        const email = document.getElementById('email').value;
        const name = document.getElementById('name').value;

        const response = await fetch("/create-payment-intent", {
            method: "POST",
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ email, name })
        })
        const { clientSecret } = await response.json();

        const appearance = { theme: 'flat' };
        const elements = stripe.elements({ clientSecret, appearance });
        const paymentElement = elements.create('payment')
        paymentElement.mount('#payment-element')

        setLoading(true);

        const { error } = await stripe.confirmPayment({
            elements,
            confirmParams: {
                return_url: (endpoint)
            }
        })
        if (error) {
            const message = document.getElementById("payment-message")
            message.innerText = error.message;
        }

        setLoading(false);
    })
})

这样,emailname变量将在表单提交时被赋予输入字段的值。之后,将使用来自该请求的响应来创建付款元素并确认付款。

英文:

Answer to your question after update (7.17.23 UPDATE)

Based on your description and the code you've shared, it appears the email and name variables are being assigned at the time of the DOMContentLoaded event. This means that the input fields' values are fetched as soon as the document has been completely loaded, which explains why the fields need to be prefilled for the code to work.

Instead, you want to fetch the input field values at the time the form is submitted, i.e., inside the submit event handler.

Try moving these lines:

const email = document.getElementById(&#39;email&#39;).value;
const name = document.getElementById(&#39;name&#39;).value;

inside the submit event handler, like so:

document.addEventListener(&#39;DOMContentLoaded&#39;, async () =&gt; {
    const {publicKey, endPoint} = await fetch(&#39;/config&#39;).then((r) =&gt; r.json())
    const stripe = Stripe(publicKey)
    const endpoint = (endPoint)

    const form = document.getElementById(&quot;payment-form&quot;)
    form.addEventListener(&#39;submit&#39;, async (e) =&gt; {
        e.preventDefault();

        const email = document.getElementById(&#39;email&#39;).value;
        const name = document.getElementById(&#39;name&#39;).value;

        const response = await fetch(&quot;/create-payment-intent&quot;, {
            method: &quot;POST&quot;,
            headers: {
                &#39;Content-Type&#39;: &#39;application/json&#39;
            },
            body: JSON.stringify({email, name})
        })
        const { clientSecret } = await response.json();

        const appearance = { theme: &#39;flat&#39; };
        const elements = stripe.elements({ clientSecret, appearance });
        const paymentElement = elements.create(&#39;payment&#39;)
        paymentElement.mount(&#39;#payment-element&#39;)

        setLoading(true);

        const {error} = await stripe.confirmPayment({
            elements,
            confirmParams: {
                return_url: (endpoint)
            }
        })
        if(error) {
            const message = document.getElementById(&quot;payment-message&quot;)
            message.innerText = error.message;
        }

        setLoading(false);
    })
})

This way, the email and name variables will be assigned the values from the input fields at the time the form is submitted. After that, a fetch request is made to the /create-payment-intent endpoint with the entered email and name. The response from this request is then used to create the payment element and confirm the payment.

huangapple
  • 本文由 发表于 2023年7月14日 05:34:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76683376.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定