Jak vytvořit formulář kreditní karty pomocí Stripe.js s React.js v Next.js

Jak vytvořit formulář kreditní karty pomocí Stripe.js a Stripe Elements a také jak získat hodnotu tohoto formuláře kreditní karty a vygenerovat zdrojový token Stripe.

Začínáme

Pro tento tutoriál, který nám poskytne výchozí bod pro naši práci, použijeme CheatCode Next.js Boilerplate. Pojďme nyní naklonovat kopii z Github:

Terminál

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

Dále cd do projektu a nainstalujte jeho závislosti:

Terminál

cd nextjs-boilerplate && npm install

Nakonec pokračujte a spusťte vývojový server:

Terminál

npm run dev

Díky tomu jsme připraveni začít.

Přístup k našim klíčům Stripe API

Než se pustíme do kódu, pro tento tutoriál budeme potřebovat přístup k účtu Stripe. Přejděte na stránku registrace na jejich webu a vytvořte si účet, pokud jste tak ještě neučinili.

Jakmile budete mít účet, přihlaste se do řídicího panelu. Mělo by to vypadat nějak takto:

Kam chceme přejít, je stránka na obrázku výše. Jak se tam dostat:

  1. Ujistěte se, že jste v pravém horním rohu přepnuli přepínač "Testovací režim" tak, aby se rozsvítil (při psaní se tato barva po aktivaci změní na oranžovou).
  2. Vlevo od tohoto přepínače klikněte na tlačítko „Vývojáři“.
  3. Na další stránce v levé navigační nabídce vyberte kartu „Klíče API“.
  4. V bloku "Standardní klíče" na této stránce vyhledejte svůj "Publikovatelný klíč."
  5. Zkopírujte tento klíč (nebojte se, je určen k tomu, aby byl přístupný veřejnosti).

Poté, jakmile budeme mít náš publikovatelný klíč, musíme otevřít projekt, který jsme právě naklonovali, a přejít na /settings/settings-development.js soubor:

/settings/settings-development.js

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

export default settings;

V tomto souboru abecedně na konci exportovaného settings objekt, chceme přidat novou vlastnost stripe a nastavte jej na objekt s jedinou vlastností:publishableKey . Pro hodnotu této vlastnosti chceme vložit publikovatelný klíč, který jste zkopírovali z panelu Stripe výše. Vložte jej a poté tento soubor uložte.

Dále, abychom mohli používat Stripe v prohlížeči, musíme načíst knihovnu Stripe.js přes Stripe CDN.

Inicializace Stripe.js v prohlížeči

Z bezpečnostních důvodů, pokud jde o hostování knihovny Stripe.js – kterou níže použijeme k vygenerování formuláře kreditní karty a načtení tokenu kreditní karty – Stripe ne dovolte nám, abychom se sami hostili. Místo toho potřebujeme načíst knihovnu prostřednictvím odkazu CDN (síť pro doručování obsahu), kterou hostuje Stripe.

Pro načtení knihovny otevřeme /pages/_document.js soubor v našem standardu, což je místo, kde Next.js nastavuje základní HTML šablonu pro náš web:

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

Zde směrem k dolní střední polovině <Head></Head> tag, který vidíme zde (pod cdn.jsdelivr.net/npm/bootstrap script), chceme vložit značku skriptu, která odkazuje na verzi Stripe.js hostovanou v CDN:<script src="https://js.stripe.com/v3/"></script> .

To je vše, co musíme udělat. Když nyní načteme naši aplikaci, Next.js načte tuto značku skriptu. Po spuštění tento skript automaticky načte Stripe v prohlížeči a poskytne nám přístup do knihovny prostřednictvím globální proměnné Stripe .

Psaní skriptu pro inicializaci Stripe

Nyní, když máme přístup k samotnému Stripe, musíme dále napsat skript, který nám umožní inicializovat Stripe pomocí publikovatelného klíče, který jsme zkopírovali dříve, a poté snadno znovu použít inicializovanou kopii knihovny.

/lib/stripe.js

import settings from "../settings";

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

export default stripe;

Zde v /lib složku standardu, který jsme naklonovali dříve, přidáváme soubor stripe.js který vtáhne naše publishableKey které jsme nastavili v našem souboru nastavení a poté, po kontrole, že globální Stripe je definována proměnná, zavolejte ji jako funkci Stripe() , předáním našeho publishableKey .

Pak, za předpokladu, že dostaneme zpět instanci (nebo null pokud se Stripe.js z nějakého důvodu nenačte), exportujeme jej z našeho souboru. Jak uvidíme dále, umožní nám to importovat „připravenou“ kopii Stripe.js bez musíme přepsat výše uvedený kód pokaždé, když chceme získat přístup ke knihovně (užitečné, pokud vytváříte aplikaci a máte v úmyslu použít Stripe ve více souborech projektu).

Vytvoření komponenty kreditní karty pomocí Stripe Elements

Nyní k té zábavnější části. Jednou z pěkných částí používání Stripe.js je, že nám umožňuje přístup k jejich knihovně Elements. To nám umožňuje rychle nastavit formulář karty v naší aplikaci, aniž bychom museli psát mnoho standardních HTML a CSS. Pro začátek nastavíme komponentu založenou na třídách v React.js (to nám poskytne lepší kontrolu nad inicializací Stripe a Elements, než bychom získali s komponentou založenou na funkcích).

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

Začínáme, zde vytváříme hrubou kostru stránky, kde prostřednictvím Elements vykreslíme naši kreditní kartu. Naštěstí je většina komponent docela jednoduchá.

Zde děláme několik věcí:

  1. Přidání značky HTML, která bude použita k zobrazení našeho formuláře.
  2. Přidání výchozích/zástupných hodnot pro dvě hodnoty stavu, které budeme používat token a cardError .
  3. Přidání zástupných funkcí pro componentDidMount() (kde nahrajeme Stripe a připojíme náš formulář karty) a handleSubmit() který použijeme k vygenerování našeho tokenu Stripe karty.

Zde bychom měli rychle upozornit na <StyledIndex></StyledIndex> komponenta, která obaluje celé označení našeho komponentu. Toto je stylizovaná komponenta, která je komponentou React generovanou knihovnou styled-components . Tato knihovna nám umožňuje vytvářet vlastní komponenty React, které představují nějaký HTML element (např. <div></div> nebo <p></p> ) a poté k němu připojte styly CSS.

Podívejme se na soubor, do kterého se to importuje z opravdu rychle:

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

Zde importujeme objekt styled z styled-components knihovna (tato je předinstalovaná v základní verzi, kterou jsme naklonovali dříve). Na tomto objektu najdeme řadu funkcí pojmenovaných podle standardních prvků HTML, například:styled.div() , styled.p() nebo styled.section() .

Pro náš formulář kreditní karty použijeme prostý <div></div> takže používáme styled.div() funkce zde. I když to tak možná nevypadá, styled.div`` část zde je ekvivalentní styled.div(``) . Myšlenka je taková, že v JavaScriptu, pokud budeme volat funkci, kde jediným argumentem je řetězec, můžeme vynechat závorky a nahradit naše jednoduché nebo dvojité uvozovky zpětnými zaškrtávacími znaménky, přičemž náš řetězec předáme jako obvykle.

V tomto souboru je to čistě syntaktická volba, aby byl náš kód v souladu s příklady nabízenými styled-components a její autoři.

Zaměřujeme se na obsah řetězce, který předáváme do styled.div() , jen přidáváme trochu lesku do našeho formuláře karet (ve výchozím nastavení nám Stripe poskytuje velmi ořezaný formulář bez stylů). Je třeba poznamenat, že zde uvidíte StripeElement--focus třída, na kterou jsou aplikovány styly (používáme vnořený selektor CSS s &, abychom řekli "pokud .credit-card prvek má také třídu StripeElement--focus , použijte tyto styly.").

Jedná se o automaticky generovanou třídu, kterou Stripe automaticky aplikuje, když se uživatel zaměří nebo „klikne“ na náš formulář karty. Používáme to ke změně barvy okraje formuláře naší karty, abychom potvrdili interakci.

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

Zpět v našem <Index /> komponentu, kde vykreslujeme označení pro naši kreditní kartu, jsme nyní připraveni skutečně připojit naší kreditní kartou. "Připojit" máme na mysli říct Stripe, aby nahradil <div className="credit-card" /> tag na naší stránce se skutečným formulářem kreditní karty od Stripe Elements.

Nahoře vidíme, že importujeme /lib/stripe.js soubor, který jsme nastavili dříve. Níže v našem componentDidMount() tuto metodu používáme k získání přístupu k .elements() funkce, která pro nás vytvoří instanci knihovny Stripe elements.

Dále, abychom mohli „připojit“ naši kreditní kartu, musíme nejprve vytvořit prvek, který ji reprezentuje (představte si to jako reprezentaci formuláře karty v paměti před tím, než bude „nakreslena“ na obrazovku). K tomu zavoláme elements.create() , předáním typu prvku, který chceme vytvořit, jako řetězec "card" jako první argument a poté objekt options jako druhý argument.

U možností nastavujeme o něco větší než výchozí velikost písma (kvůli tomu, jak Stripe připojuje formulář naší karty, bohužel nemůžeme nastavit velikost písma se zbytkem CSS v naší stylizované komponentě).

Nakonec, jakmile je náš prvek vytvořen, uložíme jej do našeho <Index></Index> třídy komponenty jako this.creditCard . To se bude hodit později, když budeme potřebovat odkaz na this.creditCard abyste získali přístup k jeho hodnotě a vygenerovali token.

Dále pod tímto kódem, abychom mohli "chytit" nebo zpracovat chyby generované prvky Stripe, musíme přidat posluchač událostí do this.creditCard . K tomu nám dává Stripe .on() metoda v tomto případě. To vyžaduje název události, kterou chceme poslouchat – zde „změna“ – a funkci zpětného volání, která se má zavolat, kdykoli tato událost nastane.

Pro naše potřeby je jedinou změnou, která nás zajímá, je if this.creditCard způsobí chybu. Uvnitř našeho change zpětné volání, bude k dispozici jako event.error . Pokud existuje, zde vezmeme event.error.message value (text popisující chybu, která se vyskytuje) a nastavte ji do stavu.

Pokud se chyba nevyskytuje (to znamená, že předchozí chyba byla opravena nebo se nikdy nevyskytla chyba), ujistěte se, že resetujete cardError on state bude prázdný řetězec.

Nakonec pod tímto change event handler, konečně se dostaneme do bodu, kdy připojíme náš formulář Stripe elementů pomocí this.creditCard.mount() . Všimněte si, že předáváme className nastavíme na <div></div> dole v našem render() metodu k této funkci. Toto řekne Stripeovi, aby vložil nebo "namontoval" vytvořené prvky na toto místo.

Těsně pod tím můžeme také vidět, že podmíněně renderujeme naše cardError pokud má hodnotu (nezapomeňte, že jsme to stylizovali dříve v našem /pages/index.css.js soubor).

I když se nám tímto technicky dostane na stránku formulář kreditní karty, na závěr se naučíme, jak získat přístup k hodnotě zadané do formuláře naší kreditní karty a převést ji na zdrojový token Stripe.

Generování tokenu Stripe

Aby byl náš formulář užitečný, nyní se naučíme, jak generovat to, co je známé jako zdrojový token Stripe. Vzhledem k různým zákonům týkajícím se přenosu finančních dat (např. PCI Compliance) je nabízení formuláře kreditní karty o něco složitější než shromažďování neškodnějších forem dat, jako je jméno nebo e-mailová adresa.

Vzhledem k tomu, že dodržování tohoto druhu regulace představuje pro malé podniky a nezávislé provozovatele značnou zátěž, zasahují společnosti jako Stripe, aby problém vyřešily. Fungují jako prostředník mezi údaji o kreditní kartě vašeho zákazníka a vašimi servery. Namísto kopírování dat kreditní karty přímo na váš vlastní server – a tedy nutnosti dodržovat zákony PCI – předáváte data společnosti Stripe, jejíž servery/kód již PCI vyhovují (a slibujete, že budou v budoucnu).

Mechanismus, který Stripe používá ke správě tohoto procesu, je známý jako zdrojový token (zde je zdrojem „platební zdroj“, jako je kreditní karta nebo bankovní účet). Když používáme Stripe.js, navážeme zabezpečené připojení přes HTTPS zpět k serverům Stripe, pošleme jim údaje o kartě, které zadá náš uživatel, a Stripe odpoví jedinečným tokenem, který představuje danou kreditní kartu. Aby bylo možné skutečně nabíjet tuto kartu, předáme tento jedinečný token spolu s našimi dalšími požadavky Stripe na našem vlastním serveru. Když to uděláme, Stripe „vyhledá“ skutečná data kreditní karty spojená s tímto tokenem na svých vlastních zabezpečených serverech/databázi.

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

Zpět v našem <Index></Index> a zaměřujeme se na náš handleSubmit() zavoláme stripe.createToken() předáváním this.creditCard hodnotu, kterou jsme nastavili dříve. Z toho Stripe ví, jak získat aktuální vstupní hodnotu. V zákulisí převezme tuto hodnotu, přenese ji na své vlastní servery a poté odpoví. Tato odpověď je zachycena zde v .then() zpětné volání (očekáváme stripe.createToken() vrátit JavaScript Promise) zde v našem kódu.

K tomuto zpětnému volání očekáváme, že dostaneme objekt s token vlastnost na něm, která je sama o sobě objektem, který má náš skutečný zdrojový token uložený ve svém .id vlastnictví. Zde, za předpokladu, že error hodnota také obsažená v tomto objektu odpovědi not definováno, vezmeme to token.id a nastavte jej zpět do stavu naší komponenty jako this.state.token (this.setState() upravuje this.state hodnotu naší součásti).

A je to! V tomto okamžiku bychom použili token.id obdrželi jsme a předali jsme to našim vlastním serverům, abychom je pak předali Stripe. Pro otestování můžeme zadat číslo karty 4242 4242 4242 4242 , předáním budoucího data vypršení platnosti a kódu CVC.

Zabalení

V tomto tutoriálu jsme se naučili, jak vygenerovat formulář kreditní karty pomocí knihovny Stripe Elements, která je součástí Stripe.js. Naučili jsme se, jak zahrnout Stripe.js do našeho HTML a inicializovat jej pomocí našeho publikovatelného klíče, který jsme získali z řídicího panelu Stripe, a poté importovat tuto instanci, abychom vygenerovali náš formulář. Také jsme se naučili, jak získat vstup našeho uživatele přes Stripe.js a poté jej předat Stripe's .createToken() způsob vygenerování tokenu zabezpečené karty pro použití jinde v naší aplikaci.