Formular-ID

Gatsby

Ein Gatsby-Formular, das schon im statischen HTML vor der Hydration funktioniert, danach mit fetch erweitert wird, plus eine Gatsby Function für Posts mit einem geheimen Schlüssel.

Gatsby rendert jede Seite beim Build zu HTML. Gib dem Formular eine echte action, dann sendet es, bevor React hydriert oder falls das Bundle nicht lädt; nach der Hydration sendet die Komponente per fetch und zeigt das Ergebnis direkt an.

Aus dem Browser senden

  1. Füge die Formular-ID hinzu

    .env.production
    GATSBY_IKIFORM_FORM_ID=frm_xxxxxxxxxxxxxxxx

    Gatsby gibt nur Variablen, die mit GATSBY_ beginnen, an Browser-Code weiter und fügt sie beim Build inline ein. Füge dieselbe Zeile für gatsby develop zu .env.development hinzu.

  2. Füge die Komponente hinzu

    src/components/contact-form.js
    import * as React from "react";
    
    const endpoint = `https://ikiform.com/f/${process.env.GATSBY_IKIFORM_FORM_ID}`;
    
    export default function ContactForm() {
      const [status, setStatus] = React.useState("idle");
      const [message, setMessage] = React.useState("");
    
      async function onSubmit(event) {
        event.preventDefault();
        setStatus("sending");
        try {
          const response = await fetch(endpoint, {
            method: "POST",
            headers: { Accept: "application/json" },
            body: new FormData(event.currentTarget),
          });
          const result = await response.json();
          if (result.ok) return setStatus("sent");
          setMessage(result.error.message);
        } catch {
          setMessage("Couldn't reach the server. Try again.");
        }
        setStatus("error");
      }
    
      if (status === "sent") return <p>Thanks, we got it.</p>;
    
      return (
        <form action={endpoint} method="post" onSubmit={onSubmit}>
          <label>
            Email
            <input name="email" type="email" autoComplete="email" required />
          </label>
          <label>
            Message
            <textarea name="message" rows={5} />
          </label>
          <input type="hidden" name="_redirect" value="https://example.com/thanks/" />
          <input name="_gotcha" type="text" tabIndex={-1} autoComplete="off" hidden />
          {status === "error" ? <p role="alert">{message}</p> : null}
          <button disabled={status === "sending"}>Send</button>
        </form>
      );
    }

    Rendere sie auf einer beliebigen Seite, zum Beispiel src/pages/contact.js, und füge src/pages/thanks.js für die Weiterleitung ohne JavaScript hinzu. Für Feldfehler und die Menschlichkeitsprüfung des SDK erweitere sie wie im React-Guide.

Aus einer Gatsby Function senden

Eine Gatsby Function kann den Post mit einem geheimen Schlüssel weiterleiten, der die erlaubten Domains und die Menschlichkeitsprüfung überspringt. Sie läuft nur auf Hosts, die Gatsby Functions unterstützen, etwa Netlify mit dem Gatsby-Adapter; ein rein statischer Host wie GitHub Pages kann sie nicht ausführen. Speichere IKIFORM_FORM_ID und einen geheimen Schlüssel mit dem Scope submissions:write als IKIFORM_SECRET_KEY, ohne das Präfix GATSBY_, damit sie nie den Browser erreichen.

src/api/contact.js
export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).end();
  const response = await fetch(`https://ikiform.com/f/${process.env.IKIFORM_FORM_ID}`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
      Authorization: `Bearer ${process.env.IKIFORM_SECRET_KEY}`,
    },
    body: JSON.stringify(req.body),
  });
  res.status(response.status).json(await response.json());
}

Gatsby parst JSON- und form-encoded Bodies in req.body, daher kann die Seite auf beide Arten an /api/contact senden. Alle Posts teilen sich dann für Rate-Limits die IP-Adresse deiner Function; siehe Von einem Server.

Erlaubte Domains

Das gilt für Posts aus dem Browser. Posts aus der Gatsby Function nutzen einen geheimen Schlüssel und überspringen die Prüfung.

Wo das Formular läuftZu Allowed domains hinzufügen
gatsby develop und gatsby servelocalhost. Passt auf http://localhost:8000 und http://localhost:9000: Ikiform vergleicht nur den Hostnamen, nie den Port.
Deine Domainexample.com, was auch www.example.com abdeckt
Netlifyyour-site.netlify.app. Deploy Previews (deploy-preview-12--your-site.netlify.app) und Branch Deploys (branch--your-site.netlify.app) sind keine Subdomains davon, füge also den exakten Preview-Host hinzu, während du eine testest.
Cloudflare Pagesyour-project.pages.dev. Preview-URLs wie abc123.your-project.pages.dev sind Subdomains davon und passen daher bereits.
  • Füge niemals netlify.app oder pages.dev allein hinzu. Jede Site auf diesem Host würde passen, auch die von anderen Leuten.

Test-Checkliste

  1. Starte gatsby build und öffne public/contact/index.html. Die action des Formulars sollte mit deiner Formular-ID enden, nicht mit undefined.
  2. Starte gatsby serve mit localhost in den erlaubten Domains und sende ab. Die Dankesnachricht sollte das Formular ersetzen.
  3. Schalte JavaScript aus, lade neu und sende ab. Lokal solltest du die Dankesseite von Ikiform sehen, auf deiner https:-Domain /thanks/.
  4. Wenn du die Function nutzt, sende in einer Deploy-Preview an /api/contact und prüfe, dass die Einsendung in Ikiform erscheint.

Fehlerbehebung

Was du siehstWarumLösung
404 not_found, und die action endet auf /f/undefinedDie Variable hat nicht das Präfix GATSBY_ oder war beim Build nicht gesetztNenne sie GATSBY_IKIFORM_FORM_ID und baue neu.
Die Function antwortet mit 403 forbiddenDer geheime Schlüssel stammt aus einem anderen Workspace, wurde widerrufen oder hat kein submissions:writeErstelle einen geheimen Schlüssel mit diesem Scope.
/api/contact gibt nach dem Deploy 404 zurückDer Host liefert nur statische Dateien ausDeploye auf einen Host mit Gatsby Functions oder nutze die Browser-Version.
Einsendungen landen im Spamfilter mit origin_mismatchDie sendende Seite steht nicht in den erlaubten Domains des FormularsFüge den Host aus der Tabelle oben hinzu. Mit Reject bekommen dieselben Requests stattdessen 403 origin_not_allowed.