JavaScript >> Javascript 文檔 >  >> React

如何在 Next.js 中使用 Stripe.js 和 React.js 構建信用卡表單

如何使用 Stripe.js 和 Stripe Elements 創建信用卡表單,以及如何檢索該信用卡表單的值並生成 Stripe 源令牌。

開始使用

對於本教程,為了給我們的工作提供一個起點,我們將使用 CheatCode Next.js 樣板。現在讓我們從 Github 克隆一個副本:

終端

git clone https://github.com/cheatcode/nextjs-boilerplate.git

接下來,cd 進入項目並安裝其依賴項:

終端

cd nextjs-boilerplate && npm install

最後,繼續啟動開發服務器:

終端

npm run dev

有了這個,我們就可以開始了。

訪問我們的 Stripe API 密鑰

在我們深入研究代碼之前,對於本教程,我們需要訪問一個 Stripe 帳戶。如果您還沒有,請前往他們網站上的註冊頁面並創建一個帳戶。

擁有帳戶後,登錄儀表板。它應該看起來像這樣:

我們要導航到的頁面是上圖所示的頁面。到達那裡:

  1. 確保您已在右上角切換了“測試模式”開關,使其亮起(在撰寫本文時,它會在激活時變為橙色)。
  2. 在該切換按鈕的左側,點擊“開發者”按鈕。
  3. 在下一頁的左側導航菜單中,選擇“API 密鑰”標籤。
  4. 在此頁面的“標準密鑰”塊下,找到您的“可發布密鑰”。
  5. 複製此密鑰(別擔心,它旨在向公眾公開)。

接下來,一旦我們有了可發布的密鑰,我們需要打開我們剛剛克隆的項目並導航到 /settings/settings-development.js 文件:

/settings/settings-development.js

const settings = {
  graphql: { ... },
  meta: { ... },
  routes: { ... },
  stripe: {
    publishableKey: "<Paste your publishable key here>",
  },
};

export default settings;

在此文件中,按字母順序位於導出的 settings 底部 對象,我們要添加一個新屬性 stripe 並將其設置為具有單個屬性的對象:publishableKey .對於此屬性的值,我們要粘貼您從上面的 Stripe 儀表板複製的可發布密鑰。粘貼進去,然後保存這個文件。

接下來,為了在瀏覽器中使用 Stripe,我們需要通過 Stripe CDN 加載 Stripe.js 庫。

在瀏覽器中初始化 Stripe.js

出於安全考慮,在託管 Stripe.js 庫時——我們將在下面使用它來生成我們的信用卡表單並檢索信用卡令牌——Stripe 允許我們自行託管。相反,我們需要通過由 Stripe 託管的 CDN(內容分發網絡)鏈接來加載庫。

要加載庫,我們將打開 /pages/_document.js 我們的樣板文件中的文件是 Next.js 為我們的網站設置基本 HTML 模板的地方:

/pages/_document.js

import Document, { Html, Head, Main, NextScript } from "next/document";
import { ServerStyleSheet } from "styled-components";

export default class extends Document {
  static async getInitialProps(ctx) { ... }

  render() {
    const { styles } = this.props;

    return (
      <Html lang="en">
        <Head>
          ...
          <script
            src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf"
            crossOrigin="anonymous"
          ></script>
          <script src="https://js.stripe.com/v3/"></script>
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

在這裡,朝向 <Head></Head> 的下半部分 我們在這裡看到的標籤(在 cdn.jsdelivr.net/npm/bootstrap 腳本),我們要粘貼指向 CDN 託管版本的 Stripe.js 的腳本標籤:<script src="https://js.stripe.com/v3/"></script> .

這就是我們需要做的。當我們現在加載我們的應用程序時,Next.js 將加載這個腳本標籤。當它運行時,這個腳本會自動在瀏覽器中加載 Stripe,並讓我們通過全局變量 Stripe 訪問這個庫 .

編寫腳本初始化 Stripe

現在我們可以訪問 Stripe 本身,接下來,我們需要編寫一個腳本,允許我們使用我們之前複製的可發布密鑰初始化 Stripe,然後輕鬆地重新使用該庫的初始化副本。

/lib/stripe.js

import settings from "../settings";

const stripe =
  typeof Stripe !== "undefined" ? Stripe(settings.stripe.publishableKey) : null;

export default stripe;

在這裡,在 /lib 我們之前克隆的樣板的文件夾,我們正在添加一個文件 stripe.js 這將拉入我們的 publishableKey 我們在設置文件中設置,然後在檢查全局 Stripe 變量已定義,將其作為函數調用 Stripe() , 傳入我們的 publishableKey .

然後,假設我們返回一個實例(或 null 如果由於某種原因 Stripe.js 無法加載),我們會從我們的文件中導出它。正如我們接下來將看到的,這將允許我們導入 Stripe.js 的“準備就緒”副本沒有 每次我們想要訪問該庫時都必須重寫上述代碼(如果您正在構建一個應用程序並打算在多個項目文件中使用 Stripe,這很有幫助)。

使用 Stripe 元素創建信用卡組件

現在是有趣的部分。使用 Stripe.js 的好處之一是它讓我們可以訪問他們的 Elements 庫。這使我們可以在我們的應用程序中快速設置卡片表單,而無需編寫大量的樣板 HTML 和 CSS。首先,我們將在 React.js 中設置一個基於類的組件(這將使我們能夠更好地控制初始化 Stripe 和 Elements,而不是使用基於函數的組件)。

/pages/index.js

import React, { useEffect, useState } from "react";

import StyledIndex from "./index.css";

class Index extends React.Component {
  state = {
    token: "",
    cardError: "",
  };

  componentDidMount() {
    // We'll set up Stripe Elements here...
  }

  handleSubmit = () => {
    // We'll handle token generation for our card here...
  };

  render() {
    const { cardError, token } = this.state;

    return (
      <StyledIndex>
        <div className="credit-card" />
        {cardError && <p className="card-error">{cardError}</p>}
        <button
          onClick={() => this.handleSubmit()}
          className="btn btn-primary btn-lg mt-4"
        >
          Get Token
        </button>
        {token && (
          <div className="mt-4">
            <p className="token">{token}</p>
          </div>
        )}
      </StyledIndex>
    );
  }
}

Index.propTypes = {
  // prop: PropTypes.string.isRequired,
};

export default Index;

開始設置,在這裡,我們正在為我們將通過 Elements 呈現信用卡的頁面創建一個粗略的框架。幸運的是,大部分組件都非常簡單。

在這裡,我們正在做一些事情:

  1. 添加將用於顯示我們的表單的 HTML 標記。
  2. 為我們將使用的兩個狀態值添加默認/佔位符值 tokencardError .
  3. componentDidMount() 添加佔位符函數 (我們將加載 Stripe 並掛載我們的卡片表單)和 handleSubmit() 我們將使用它來生成我們的 Stripe 卡令牌。

值得注意的是,在這裡,我們應該快速注意 <StyledIndex></StyledIndex> 包裝整個組件標記的組件。這是一個樣式化組件,它是由庫 styled-components 生成的 React 組件 .這個庫允許我們創建代表一些 HTML 元素的自定義 React 組件(例如,一個 <div></div><p></p> ),然後將 CSS 樣式附加到它。

讓我們看一下從真正快速導入的文件:

/pages/index.css.js

import styled from "styled-components";

export default styled.div`
  .credit-card {
    border: 1px solid #eee;
    box-shadow: 0px 0px 2px 2px rgba(0, 0, 0, 0.02);
    padding: 20px;
    border-radius: 3px;
    font-size: 18px;

    &.StripeElement--focus {
      border: 1px solid #ffcc00;
      box-shadow: 0px 0px 2px 2px rgba(0, 0, 0, 0.02);
    }
  }

  .card-error {
    background: #ea4335;
    color: #fff;
    padding: 20px;
    border-radius: 3px;
    margin-top: 10px;
  }

  .token {
    background: #eee;
    padding: 20px;
    border-radius: 3px;
    font-size: 16px;
    color: #444;
  }
`;

在這裡,我們導入對象 styled 來自 styled-components 庫(這是預裝在我們之前克隆的樣板文件中)。在這個對像上,我們可以找到一系列以標準 HTML 元素命名的函數,例如:styled.div() , styled.p() , 或 styled.section() .

對於我們的信用卡表單,我們將使用純 <div></div> 標籤,所以我們使用 styled.div() 在這裡發揮作用。雖然它可能看起來不像,但 styled.div`` 這裡的部分相當於 styled.div(``) .這個想法是,在 JavaScript 中,如果我們要調用一個函數,其中唯一的參數是一個字符串,我們可以省略括號並用反引號替換我們的單引號或雙引號,正常傳遞我們的字符串。

在這個文件中,這純粹是一種語法選擇,以使我們的代碼與 styled-components 提供的示例保持一致 及其作者。

關注我們傳遞給 styled.div() 的字符串的內容 ,我們只是在卡片表單中添加了一點點潤色(默認情況下,Stripe 為我們提供了一個非常精簡的表單,沒有樣式)。值得注意的是,在這裡,您會看到 StripeElement--focus 應用了樣式的類(我們使用帶有 &的嵌套 CSS 選擇器來表示“如果 .credit-card 元素也有類 StripeElement--focus ,應用這些樣式。”)。

這是一個自動生成的類,當用戶關注或“點擊”我們的卡片表單時,Stripe 會自動應用它。我們使用它來更改卡片表單的邊框顏色以確認交互。

/pages/index.js

import React, { useEffect, useState } from "react";
import stripe from "../lib/stripe";

import StyledIndex from "./index.css";

class Index extends React.Component {
  state = {
    token: "",
    cardError: "",
  };

  componentDidMount() {
    const elements = stripe.elements();

    this.creditCard = elements.create("card", {
      style: {
        base: {
          fontSize: "18px",
        },
      },
    });

    this.creditCard.on("change", (event) => {
      if (event.error) {
        this.setState({ cardError: event.error.message });
      } else {
        this.setState({ cardError: "" });
      }
    });

    this.creditCard.mount(".credit-card");
  }

  handleSubmit = () => {
    // We'll handle token generation for our card here...
  };

  render() {
    const { cardError, token } = this.state;

    return (
      <StyledIndex>
        <div className="credit-card" />
        {cardError && <p className="card-error">{cardError}</p>}
        <button
          onClick={() => this.handleSubmit()}
          className="btn btn-primary btn-lg mt-4"
        >
          Get Token
        </button>
        {token && (
          <div className="mt-4">
            <p className="token">{token}</p>
          </div>
        )}
      </StyledIndex>
    );
  }
}

Index.propTypes = {
  // prop: PropTypes.string.isRequired,
};

export default Index;

回到我們的 <Index /> 我們正在為我們的信用卡渲染標記的組件,現在我們已經準備好實際安裝 我們的信用卡。通過“mount”,我們的意思是告訴 Stripe 替換 <div className="credit-card" /> 使用 Stripe Elements 的實際信用卡表格在我們的頁面上標記。

在頂部,我們可以看到我們正在導入 /lib/stripe.js 我們之前設置的文件。在我們的 componentDidMount() 中 方法,我們使用它來訪問 .elements() 為我們創建 Stripe 元素庫實例的函數。

接下來,為了“掛載”我們的信用卡,我們首先需要創建代表它的元素(可以將其想像為卡片在屏幕上“繪製”之前的內存中表示)。為此,我們調用 elements.create() ,將我們要創建的元素類型作為字符串 "card" 傳入 作為第一個參數,然後一個選項對像作為第二個參數。

對於選項,我們設置的字體大小略大於默認字體大小(由於 Stripe 是如何安裝我們的卡片表單的,不幸的是,我們無法在樣式化組件中使用其餘 CSS 設置字體大小)。

最後,一旦我們的元素被創建,我們將它存儲在我們的 <Index></Index> 組件類為 this.creditCard .稍後當我們需要引用 this.creditCard 時,這將派上用場 為了訪問它的值並生成一個令牌。

在這段代碼下面,接下來,為了“捕捉”或處理 Stripe 元素產生的錯誤,我們需要在 this.creditCard 中添加一個事件監聽器 .為了做到這一點,Stripe 給了我們一個 .on() 該實例上的方法。這需要我們想要監聽的事件的名稱——這裡是“改變”——以及一個在該事件發生時調用的回調函數。

對於我們的需求,我們唯一關心的變化是 if this.creditCard 產生錯誤。我們的 change 內部 回調,這將作為 event.error .如果存在,在這裡,我們獲取 event.error.message 值(描述正在發生的錯誤的文本)並將其設置為狀態。

如果沒有錯誤(意味著先前的錯誤已被糾正或從沒有錯誤開始),我們確保重置 cardError on state 為空字符串。

最後,在這個change下面 事件處理程序,我們終於到了通過 this.creditCard.mount() 掛載我們的 Stripe 元素表單的地步 .請注意,我們傳入 className 我們在 <div></div> 上設置 在我們的 render() 這個函數的方法。這告訴 Stripe 在這個位置注入或“掛載”元素形式。

在此之下,我們還可以看到我們有條件地渲染我們的 cardError 如果它有一個值(請記住,我們之前在 /pages/index.css.js 文件)。

雖然這在技術上為我們在頁面上提供了一張信用卡表格,但最後,我們將學習如何訪問輸入到我們的信用卡表格中的值並將其轉換為 Stripe 源令牌。

生成 Stripe 令牌

為了使我們的表單有用,現在,我們將學習如何生成所謂的 Stripe 源令牌。由於有關財務數據傳輸的各種法律(例如 PCI 合規性),提供信用卡表格比收集更無害的數據形式(如姓名或電子郵件地址)涉及更多的法律複雜性。

由於遵守此類法規對小企業和獨立運營商來說是一個沉重的負擔,因此像 Stripe 這樣的公司介入解決了這個問題。他們充當客戶信用卡數據和服務器之間的中間人。您無需將信用卡數據直接複製到您自己的服務器(因此必須遵守 PCI 法律),而是將數據交給 Stripe,後者的服務器/代碼已經符合 PCI 標準(並承諾將來會這樣做)。

Stripe 用於管理此過程的機制稱為源令牌(此處,源是“支付源”,如信用卡或銀行賬戶)。當我們使用 Stripe.js 時,我們通過 HTTPS 與 Stripe 的服務器建立安全連接,將我們用戶輸入的卡數據發送給它們,然後 Stripe 以代表該信用卡的唯一令牌進行響應。為了真正充電 這張卡,我們將這個唯一的令牌與我們的其他請求一起傳遞給我們自己服務器上的 Stripe。當我們這樣做時,Stripe 在他們自己的安全服務器/數據庫上“查找”與該令牌相關聯的實際信用卡數據。

/pages/index.js

import React, { useEffect, useState } from "react";
import stripe from "../lib/stripe";

import StyledIndex from "./index.css";

class Index extends React.Component {
  state = {
    token: "",
    cardError: "",
  };

  componentDidMount() { ... }

  handleSubmit = () => {
    stripe.createToken(this.creditCard).then(({ error, token }) => {
      if (error) {
        this.setState({ cardError: error.message });
      } else {
        this.setState({ token: token.id });
      }
    });
  };

  render() {
    const { cardError, token } = this.state;

    return (
      <StyledIndex>
        <div className="credit-card" />
        {cardError && <p className="card-error">{cardError}</p>}
        <button
          onClick={() => this.handleSubmit()}
          className="btn btn-primary btn-lg mt-4"
        >
          Get Token
        </button>
        {token && (
          <div className="mt-4">
            <p className="token">{token}</p>
          </div>
        )}
      </StyledIndex>
    );
  }
}

Index.propTypes = {
  // prop: PropTypes.string.isRequired,
};

export default Index;

回到我們的 <Index></Index> 組件並專注於我們的 handleSubmit() 方法,我們調用 stripe.createToken() 方法,傳入 this.creditCard 我們之前設置的值。由此,Stripe 知道如何檢索當前輸入值。在幕後,它獲取這個值,將其傳輸到自己的服務器,然後響應。該響應在 .then() 中捕獲 回調(我們期望 stripe.createToken() 在我們的代碼中返回一個 JavaScript Promise)。

對於那個回調,我們期望得到一個帶有 token 的對象 它的屬性本身就是一個對象,我們的實際源令牌存儲在其 .id 中 財產。在這裡,假設 error 此響應對像中還包含的值是 not 已定義,我們採用 token.id 並將其設置回我們組件的狀態為 this.state.token (this.setState() 修改 this.state 我們組件的值)。

而已!此時,我們將採用 token.id 我們已經收到並將其轉發到我們自己的服務器,然後傳遞給 Stripe。測試一下,我們可以輸入卡號4242 4242 4242 4242 ,傳遞任何未來的到期日期和 CVC。

總結

在本教程中,我們學習瞭如何使用捆綁在 Stripe.js 中的 Stripe Elements 庫生成信用卡表單。我們學習瞭如何在 HTML 中包含 Stripe.js 並使用從 Stripe 儀表板獲得的可發布密鑰對其進行初始化,然後導入該實例以生成我們的表單。我們還學習瞭如何通過 Stripe.js 檢索用戶的輸入,然後將其傳遞給 Stripe 的 .createToken() 生成安全卡令牌以在我們的應用程序的其他地方使用的方法。


Tutorial JavaScript 教程
  1. HTML5 Canvas:繪製完成時獲取事件

  2. JavaScript 中的數據結構和算法(集)

  3. 如何在 JavaScript 中使用動態鍵創建對象?

  4. 需要節點——第 24 卷

  5. 嘗試過 Next.js 9.0 + TypeScript + redux-observable 並作為初學者發布

  6. 第 20-24 天:鼓機

  7. 如何創建自定義 React 掛鉤來獲取 API(使用 TypeScript)?

  1. 在 GraphQL 上

  2. 如何在分隔特定字符的同時將字符串拆分為第 n 個字母字符間隔?

  3. jQuery AutoForm 腳本 簡易表單自動完成

  4. 2021 年成為現代前端開發人員的分步指南

  5. 使用原型的無痛 JavaScript

  6. 我正在尋找用於反應應用程序的拖放頁面構建器資源

  7. 使用粉筆進行彩色 Node.js 消息記錄

  1. JavaScript 和 React 中的事件冒泡和事件捕獲——初學者指南

  2. 全棧 React 和 Node.js - 讓客戶端和服務器對話

  3. Twilio 和 Node - 發送您的第一條短信

  4. 在 Svelte 中預加載圖像