Anleitungen

Anleitungen15 Min. Lesezeit

So funktioniert das Absenden eines HTML-Formulars

Was ein Browser beim Absenden eines Formulars tut: welche Felder er sendet, wie er sie kodiert, was der Server antworten sollte und wie Ikiform antwortet.

Preet SutharGründer, Ikiform

Wenn jemand auf Absenden drückt, prüft der Browser die Constraints des Formulars, sammelt jedes benannte und aktivierte Steuerelement, kodiert sie mit dem enctype des Formulars und sendet sie mit der method des Formulars an die action-URL. Der Server antwortet wie bei jedem Seitenaufruf, und ein sauber gebauter Server beantwortet einen erfolgreichen POST mit einer 303-Weiterleitung, damit ein Neuladen das Formular nicht doppelt sendet. Richte action auf ein Formular-Backend wie Ikiform aus, und du bekommst diese Weiterleitung, Feldvalidierung und Spamfilterung ganz ohne eigenen Server.

HTML-Formulare sind älter als JavaScript und immer noch der zuverlässigste Weg, Daten von einer Webseite zu senden. Sie funktionieren ohne Skripte, auf langsamen Handys und in jedem Baukasten, in den du Markup einfügen kannst. Die meisten Formular-Bugs entstehen, weil man nicht weiß, was der Browser von sich aus tut. Deshalb geht diese Anleitung ein Absenden Schritt für Schritt durch und zeigt dann, wie ein Formular-Backend dazu passt.

Was passiert, wenn du auf Absenden drückst

Ein Absenden ist eine normale Navigation mit angehängtem Body. Der Browser erledigt vier Dinge, bevor irgendetwas die Seite verlässt, übergibt dann den Request ans Netzwerk und lädt, was zurückkommt.

Was ein Browser zwischen dem Klick auf Absenden und der nächsten Seite tutim Browserüber das NetzwerkabsendenButton,Enter-TasteoderrequestSubmit()Constraint-Prüfungrequired,type, pattern,min und maxFormulardatensatznur benannte,aktiveElementekodierenurlencodedodermultipartMeldung amFeldnichts wirdgesendetPOST anactionSec-Fetch-Mode:navigateServerantwortet303 SeeOtherGETLocationdieDankeseitegültigungültigfolgenWas ein Browser zwischen dem Klick auf Absenden und der nächsten Seite tutim Browserüber das NetzwerkabsendenButton, Enter-TasteoderrequestSubmit()Constraint-Prüfungrequired, type,pattern, min und maxFormulardatensatznur benannte, aktiveElementekodierenurlencoded odermultipartMeldungam Feldnichts wirdgesendetPOST an actionSec-Fetch-Mode:navigateServerantwortet303 See OtherGET Locationdie Dankeseitegültigfolgenungültig
  1. Ein Absende-Button, die Enter-Taste in einem Textfeld oder form.requestSubmit() startet das Absenden und löst ein submit-Event aus.
  2. Sofern das Formular kein novalidate hat, prüft der Browser die Constraints jedes Steuerelements. Das erste ungültige bekommt eine Meldung, und nichts wird gesendet.
  3. Der Browser baut den Formulardatensatz aus jedem Steuerelement, das einen name hat und nicht deaktiviert ist.
  4. Er kodiert diesen Datensatz mit dem enctype des Formulars, standardmäßig urlencoded.
  5. Er navigiert mit der method des Formulars zur action-URL und sendet den Body mit.
  6. Der Server antwortet. Ein 303 weist den Browser an, eine andere URL per GET zu laden, und das ist die Seite, auf der der Besucher landet.
Alles oberhalb der Linie passiert ganz ohne Netzwerk. Ein Listener für das submit-Event kann den Ablauf beim ersten Schritt stoppen und mit fetch übernehmen.

Die Attribute, die den Request bestimmen

Fünf Attribute an <form> bestimmen, wohin die Daten gehen und wie. Jedes lässt sich für einen einzelnen Button mit einem passenden form*-Attribut überschreiben. So kann ein Formular Buttons für Send und Save draft haben, die sich unterschiedlich verhalten.

AttributStandardWas es tutÜberschreiben am Button
actionDie eigene URL der SeiteDie URL, die die Daten empfängt. Relative Werte werden relativ zur Seite aufgelöst. Siehe das action-Attributformaction
methodgetget packt die Felder in den Query-String der URL. post sendet sie als Body. dialog schließt ein <dialog>, ohne etwas zu sendenformmethod
enctypeapplication/x-www-form-urlencodedWie ein post-Body kodiert wird. multipart/form-data ist für Dateien nötig. text/plain ist zum Debuggen gedachtformenctype
novalidateAusÜberspringt beim Absenden die Constraint-Prüfung des Browsersformnovalidate
target_selfWo die Antwort geladen wird. _blank öffnet einen neuen Tab, ein benanntes iframe lässt die Seite, wo sie istformtarget

Zwei Buttons, zwei Verhaltensweisen. Der zweite überspringt die Validierung, und name und value des geklickten Buttons werden den Daten hinzugefügt, damit der Server weiß, welcher gedrückt wurde:

Zwei Absende-Buttons
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <input name="email" type="email" required />
  <textarea name="details" required></textarea>
  <button name="intent" value="report">Send report</button>
  <button name="intent" value="draft" formnovalidate>Save as draft</button>
</form>

Welche Steuerelemente gesendet werden

Browser senden nur, was die HTML-Spezifikation den Formulardatensatz nennt. Die meisten Überraschungen in einem Einsendungsprotokoll kommen von diesen Regeln:

  • Ein Steuerelement braucht einen name. Eine id allein sendet nichts.
  • disabled-Steuerelemente werden übersprungen. Nutze readonly, wenn ein Wert angezeigt, gesperrt und gesendet werden soll.
  • Eine nicht angehakte Checkbox oder ein nicht gewählter Radio-Button sendet gar nichts, nicht false. Eine angehakte Checkbox ohne value sendet on.
  • Nur der Button, der das Formular abgesendet hat, wird mitgesendet, mit seinem name und value.
  • <select multiple> und Checkbox-Gruppen mit gemeinsamem Namen senden ein Paar pro ausgewähltem Wert.
  • Eingabefelder außerhalb des <form>-Elements können sich ihm mit einem form-Attribut anschließen, das die id des Formulars nennt.

Wie der Body kodiert wird

Mit dem Standard-enctype ist der Body eine Zeile aus name=value-Paaren, verbunden mit &, Leerzeichen als + und allem außerhalb eines sicheren Zeichensatzes prozentkodiert. Das ist der echte Request für das Meldeformular weiter unten, so wie der Browser ihn sendet:

application/x-www-form-urlencoded
POST /f/frm_xxxxxxxxxxxxxxxx HTTP/1.1
Host: ikiform.com
Content-Type: application/x-www-form-urlencoded
Origin: https://example.com
Sec-Fetch-Mode: navigate

email=ada%40example.com&page=https%3A%2F%2Fexample.com%2Fpricing&severity=broken&details=The+annual+toggle+does+nothing&_redirect=https%3A%2F%2Fexample.com%2Freport-sent&_gotcha=

multipart/form-data verpackt jedes Feld in einen eigenen Teil mit einem Boundary-String, den der Browser wählt. Das ist größer, kann aber Dateien transportieren. Ikiform liest beides. Bei text/plain lässt sich nicht zuverlässig erkennen, wo ein Wert endet, deshalb lehnt Ikiform es mit 415 unsupported_media_type ab.

multipart/form-data
POST /f/frm_xxxxxxxxxxxxxxxx HTTP/1.1
Host: ikiform.com
Content-Type: multipart/form-data; boundary=----formdata7f3a

------formdata7f3a
Content-Disposition: form-data; name="email"

ada@example.com
------formdata7f3a
Content-Disposition: form-data; name="severity"

broken
------formdata7f3a--
Egal welche Kodierung: Halte die Seite in UTF-8. Ikiform dekodiert jeden Body als UTF-8 und lehnt andere Zeichensätze mit 415 unsupported_charset ab. Datei-Uploads werden noch nicht unterstützt. Ein Post mit einer Datei bekommt 422 files_not_supported.

Vier Wege, ein Formular abzusenden

Ein einfacher Post ist nur eine Option. Jeder der folgenden Ansätze ist irgendwo eine gute Wahl; was sich ändert, ist, wer die Antwort verarbeitet und was ohne Skripte passiert.

AnsatzStark beiNachteile
Einfaches method="post" mit WeiterleitungFunktioniert ohne JavaScript, in jedem Baukasten. Der Browser kümmert sich um Ladezustand, Zurück und NeuladenEin vollständiger Seitenaufruf. Feldfehler brauchen eine serverseitig gerenderte Seite oder die Fehlerseite des Backends
fetch mit FormDataKein Neuladen. Du entscheidest, wie Erfolg und jeder Feldfehler aussehenLadezustand, Netzwerkfehler und Fokus liegen bei dir. Ohne Sorgfalt bricht es, wenn Skripte aus sind. Siehe ohne Neuladen der Seite
Form Actions von Frameworks, etwa Server Actions in Next.js oder Form Actions in SvelteKitDein Server sieht den Post zuerst, und dasselbe Formular funktioniert vor und nach der HydrationDu brauchst eine Server-Runtime, und der Request ans Backend geht von deinem Server aus, was Rate-Limits und Origin-Prüfungen verändert
method="get"Such- und Filterformulare. Das Ergebnis hat eine teilbare URLFelder landen in URL, Verlauf und Serverlogs. Nie für personenbezogene Daten oder alles, was Zustand ändert

Fang mit dem einfachen Post an und setze fetch obendrauf. So funktioniert das Formular weiter, wenn ein Skript nicht lädt, und das passiert öfter, als die meisten Analytics zeigen.

Was der Server antworten sollte

Der Browser behandelt die Antwort auf einen POST als neue Seite. Ist diese Seite die Antwort selbst, mit Status 200, merkt sich der Browser, dass sie von einem POST stammt. Lädst du neu, bietet er an, das Formular erneut zu senden; bei Zurück und Vor tun manche Browser dasselbe. So zahlen Leute doppelt, und der Support bekommt dieselbe Nachricht dreimal.

Die Lösung ist das Post/Redirect/Get-Muster. Der Server verarbeitet den POST und antwortet dann mit 303 See Other und einem Location-Header. Der Browser lädt diese URL per GET, und die Seite, die der Besucher sieht, stammt von einem GET, also ist Neuladen harmlos.

Einen POST mit einer Seite beantworten im Vergleich zu einer 303-Weiterleitungmit einer Seite antworten (200)mit Weiterleitung antworten (303)POST/report200 mitDanke-HTMLdie Seitestammt voneinem POSTneu laden"ErneutesSendenbestätigen"erneuterPOSTein DuplikatPOST/report303 SeeOtherLocation:/report-sentGET/report-sentneu ladenlädt nur denGET neuEinen POST mit einer Seite beantworten im Vergleich zu einer 303-Weiterleitungmit einer Seite antworten (200)mit Weiterleitung antworten (303)POST /report200 mit Danke-HTMLdie Seite stammt von einem POSTneu laden"Erneutes Senden bestätigen"erneuter POSTein DuplikatPOST /report303 See OtherLocation: /report-sentGET /report-sentneu ladenlädt nur den GET neu
  1. Bei einer 200-Antwort sendet der Browser das Formular und zeigt den Response-Body als Seite an.
  2. Diese Seite ist an den POST gebunden, also fragt ein Neuladen nach erneutem Senden, und eine Bestätigung sendet die Daten noch einmal.
  3. Bei einer 303-Antwort sendet der Browser das Formular und wird angewiesen, eine andere URL zu laden.
  4. Er lädt diese URL per GET. Ein Neuladen wiederholt nur den GET, also wird nichts doppelt gesendet.
Ikiform beantwortet einen Browser-Post immer mit einem 303, dein Formular bekommt dieses Verhalten also gratis.
StatusWas der Browser als Nächstes tutEinsatz
303 See OtherGET auf die Location, Body verworfenNach jedem erfolgreichen Formular-Post
302 FoundBrowser wechseln in der Praxis zu GET, aber die Spezifikation erlaubt, die Methode beizubehaltenÄltere Server. Besser 303
307 und 308Denselben POST mit demselben Body an der neuen URL wiederholenEinen Endpunkt verschieben, nie eine Dankeseite
200 mit HTMLSeite anzeigen; Neuladen bietet erneutes Senden anFormular mit Fehlern erneut anzeigen
4xx mit HTMLFehlerseite anzeigenFehler, die der Besucher per Zurück beheben kann
Post/Redirect/Get
HTTP/1.1 303 See Other
Location: https://example.com/report-sent
X-Request-Id: req_01k7v2c9t3e8m5q4x6z0a1b2c3

GET /report-sent HTTP/1.1
Host: example.com

Wie Ikiform antwortet

Ein Endpunkt, https://ikiform.com/f/<formId>, antwortet Browsern und Code. Er entscheidet pro Request, ob er mit Seiten oder mit JSON antwortet, anhand von Headern, die der Browser selbst setzt:

RequestAntwort
Accept enthält application/jsonJSON
Der Body ist JSONJSON
Sec-Fetch-Mode: navigate, also jeder einfache Formular-PostWeiterleitung oder gehostete Seite
Jeder andere Sec-Fetch-Mode, etwa cors von fetchJSON
Kein Sec-Fetch-Mode, und Accept enthält text/htmlWeiterleitung oder gehostete Seite
Alles andere, etwa curlJSON

Sec-Fetch-Mode ist ein Header, den der Browser setzt und den Skripte auf der Seite nicht ändern können. Ein Formular-Post, der im Tab navigiert, sendet navigate; ein fetch-Aufruf sendet bei einem Cross-Site-Request cors. Dasselbe Formular bekommt also eine Weiterleitung, wenn es auf die einfache Art sendet, und JSON, wenn dein Skript es sendet, ohne dass du etwas umschalten musst. Die vollständige Tabelle steht unter JSON oder eine Weiterleitung.

Derselbe Ikiform-Endpunkt beantwortet einen einfachen Formular-Post und einen fetch-Aufrufeinfacher Formular-Postfetch oder Accept: application/jsonBrowser navigiertSec-Fetch-Mode:navigateIkiformSeitenmodus303 auf deineSeiteoder die gehosteteDankeseitegehosteteFehlerseiteProbleme nachFeldlabel, echterStatusSkript sendetSec-Fetch-Mode: corsIkiformJSON-Modus201 mit der ID{ ok: true, id }JSON-Fehlererror.fields nachFeld-IDabgelehntabgelehntDerselbe Ikiform-Endpunkt beantwortet einen einfachen Formular-Post und einen fetch-Aufrufeinfacher Formular-Postfetch oder Accept: application/jsonBrowsernavigiertSec-Fetch-Mode:navigateIkiformSeitenmodus303 auf deineSeiteoder die gehosteteDankeseitegehosteteFehlerseiteProblemenachFeldlabel,echterStatusSkript sendetSec-Fetch-Mode:corsIkiformJSON-Modus201 mit der ID{ ok: true, id }JSON-Fehlererror.fieldsnachFeld-IDabgelehntabgelehnt
  1. Ein einfacher Formular-Post navigiert im Tab, also sendet der Browser Sec-Fetch-Mode: navigate.
  2. Ikiform antwortet im Seitenmodus: mit einer 303-Weiterleitung bei Erfolg oder einer gehosteten Fehlerseite mit dem echten Status des Fehlers.
  3. Ein fetch-Aufruf sendet Sec-Fetch-Mode: cors, oder dein Code fordert über den Accept-Header JSON an.
  4. Ikiform antwortet im JSON-Modus: 201 mit der ID der Einsendung oder dem Fehler-Envelope mit Feldfehlern nach Feld-ID.
Du konfigurierst den Modus nicht. Er ergibt sich daraus, wie der Request gestellt wurde.

Wo ein erfolgreicher Post landet

Ein erfolgreicher Browser-Post bekommt einen 303. Ikiform wählt das Ziel in dieser Reihenfolge:

  1. Die Einstellung Redirect after submit (Weiterleitung nach dem Absenden) des Formulars im Dashboard. Jede http:- oder https:-URL funktioniert, weil nur dein Workspace sie setzen kann.
  2. Ein _redirect-Feld im Post, oder _next, wenn es kein _redirect gibt, sofern es eine https:-URL ohne Benutzername, Passwort oder eigenen Port ist und auf einer der Allowed domains des Formulars oder einer Subdomain davon liegt.
  3. Andernfalls die gehostete Dankeseite unter /f/<formId>/thanks. Kam der Post von einer https:-Seite auf einer erlaubten Domain, verlinkt sie dorthin zurück.

Ein _redirect, das gegen eine Regel verstößt, wird ignoriert, nie als Fehler behandelt, und ein Formular ohne erlaubte Domains ignoriert _redirect komplett. So kann niemand dein Formular nutzen, um Besucher auf eine Site seiner Wahl umzuleiten. Weiterleitung nach dem Absenden behandelt Dankeseiten ausführlich, und die vollständigen Regeln stehen unter HTML-Formulare.

Wenn ein Post abgelehnt wird

Im Seitenmodus zeigt ein abgelehnter Post eine gehostete Fehlerseite mit dem echten HTTP-Status des Fehlers. Bei einem Validierungsfehler listet sie jedes Problem unter dem Label deines Felds auf und verlinkt auf die Seite, von der der Post kam. Der Back-Button des Browsers führt meist zurück zum Formular, mit dem, was der Besucher eingetippt hat; der Link lädt die Seite neu. Im JSON-Modus kommt derselbe Fehler als ein Envelope zurück. Jeder Code steht unter Fehler.

422 im JSON-Modus
{
  "ok": false,
  "error": {
    "code": "validation_failed",
    "message": "Some fields are invalid.",
    "fields": {
      "page": ["Enter a valid URL"],
      "details": ["Must be at least 20 characters"]
    }
  },
  "request_id": "req_01k7v2c9t3e8m5q4x6z0a1b2c3"
}

Spam ist das Einzige, das nie wie ein Fehler aussieht. Ein Post, der als Spam bewertet wird, bekommt denselben 303 oder 201 wie ein echter, damit ein Bot nichts lernt, und er löst keine E-Mail und keinen Webhook aus.

Das Formular in deinem Stack

Hier ist ein echtes Formular, eine Meldung für eine kaputte Seite, in jedem Stack. Wähle deinen; die Auswahl gilt für jedes Codebeispiel in diesen Anleitungen. Die Felddefinition unten ist dieselbe, die Ikiform auf dem Server durchsetzt, also probier es aus: Halte die Details kurz oder gib example als Adresse ein, und du bekommst den 422, den dein Formular bekäme.

Vorschau

Führt den Validator von Ikiform in deinem Browser aus. Es wird nichts gesendet.

Füge diese Definition im Tab Fields (Felder) des Formulars im Dashboard ein, und Ikiform validiert jeden Post dagegen. Siehe Felder und Validierung.

Ganz ohne Skript. Der Browser prüft required, type und minlength, sendet die Felder als urlencoded Text, folgt Ikiforms 303 zu deiner _redirect-Seite und zeigt Ikiforms Fehlerseite, wenn der Server den Post ablehnt.

report.html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <label for="email">Your email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />

  <label for="page">Page address</label>
  <input id="page" name="page" type="url" required placeholder="https://example.com/pricing" />

  <label for="severity">How bad is it</label>
  <select id="severity" name="severity">
    <option value="cosmetic">Looks wrong</option>
    <option value="broken">Something doesn't work</option>
    <option value="blocking">I can't continue</option>
  </select>

  <label for="details">What happened</label>
  <textarea id="details" name="details" rows="5" minlength="20" maxlength="4000" required></textarea>

  <input type="hidden" name="_redirect" value="https://example.com/report-sent" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send report</button>
</form>
Die serverseitigen Versionen senden mit einem Secret Key, daher überspringt Ikiform Allowed domains und seine Menschlichkeitsprüfung. Jeder Post kommt dann von der IP deines Servers, und das Standard-Limit von 5 pro Minute und Besucher zählt alle deine Besucher zusammen. Wähle für ein Formular, das du über einen Server sendest, das Rate-Limit Relaxed oder Custom, und halte IKIFORM_SECRET_KEY in reinen Server-Umgebungsvariablen.

Jede Serverversion leitet den Origin-Header des Browsers weiter, wenn es einen gibt, weil ein serverseitiges fetch keinen sendet und Ikiform ihn nutzt, um kostenlose localhost-Tests in einem Workspace ohne Tarif zu erkennen.

  • Jede Version behält eine echte method und, wo sie direkt an Ikiform sendet, eine echte action. Mit deaktivierten Skripten sendet das Formular trotzdem und bekommt den 303.
  • Der name jedes Eingabefelds ist die Feld-id in der Definition. Eine Abweichung, etwa url statt page, bekommt 422 mit Unknown field "url".
  • Das versteckte _gotcha-Feld ist der Honeypot. Bots, die es ausfüllen, werden stillschweigend als Spam gespeichert.
  • Die JavaScript-Versionen zeigen error.fields unter jedem Eingabefeld an, jeweils mit der ersten Meldung pro Feld. Die reine HTML-Version überlässt das Ikiforms Fehlerseite.

Die Docs gehen pro Framework tiefer: Next.js, Astro, SvelteKit, Nuxt, React, Vue und von einem Server.

Zwei Ebenen der Validierung

Browser-Validierung und Server-Validierung erfüllen unterschiedliche Aufgaben. Die Constraint-Prüfung des Browsers (required, type="email", minlength, pattern) gibt sofortiges Feedback, aber jeder kann sie umgehen: Ein Bot sendet direkt, und ein Skript kann form.submit() aufrufen, das die Prüfung nie ausführt. Nur auf dem Server gilt eine Regel wirklich.

RegelIm BrowserIn Ikiforms Felddefinition
Pflichtfeldrequired"required": true
E-Mailtype="email""type": "email", optional mit allowed_domains
URLtype="url""type": "url", optional mit https_only
Längeminlength, maxlengthvalidation.min_length, max_length
Nur gelistete AuswahlwerteEin <select>, das ein Bot ignoriertoptions; alles andere wird abgelehnt
Keine zusätzlichen FelderNicht möglichJedes Feld, das nicht in der Definition steht, wird abgelehnt

Ohne Definition akzeptiert Ikiform beliebige Felder und speichert sie so, wie sie ankommen. Veröffentlichst du eine, validiert Ikiform, speichert Zahlen und Checkboxen als echte Zahlen und Booleans und lehnt den Post mit 422 validation_failed ab, bevor etwas gespeichert wird. Validierung zeigt, wie beide Ebenen dasselbe sagen.

Absenden mit JavaScript

Um den Besucher auf der Seite zu halten, horche auf submit, rufe preventDefault() auf und sende new FormData(form) mit fetch. Ein paar Details entscheiden, ob das auf Anhieb funktioniert:

  • Setze Content-Type nicht selbst, wenn der Body FormData ist. Der Browser setzt multipart/form-data mit der Boundary; ein von Hand geschriebener Header hat keine Boundary, und der Body lässt sich nicht parsen.
  • Sende Accept: application/json. Ikiform würde JSON ohnehin anhand von Sec-Fetch-Mode wählen, aber der Header macht es explizit, und er gehört zu den Request-Headern, die Browser ohne Preflight cross-site senden können.
  • Ein Body aus FormData oder URLSearchParams ist ein einfacher Cross-Site-Request, also gibt es keinen Preflight. Ein JSON-Body mit Content-Type: application/json löst zuerst einen Preflight aus; Ikiform beantwortet ihn, aber das kostet einen Roundtrip.
  • form.submit() überspringt die Validierung und das submit-Event. form.requestSubmit() führt beides aus, wie ein Klick.
  • Übergib den geklickten Button als zweites Argument, new FormData(form, event.submitter), wenn sein name und value wichtig sind.

Das vollständige Muster mit Ladezustand, Fokus und Netzwerkfehlern steht unter ohne Neuladen der Seite. Die Docs zu JavaScript und fetch listen jeden Header und jedes Body-Format, das der Endpunkt annimmt.

Wähle deinen Fall

Jede dieser Seiten nimmt sich einen Teil des Absendens vor und geht weiter als der Überblick oben, mit Code für diesen Fall.

Prüfen, ob es funktioniert

Geh das einmal pro Formular in einem privaten Fenster durch. Ikiform hat keinen kostenlosen Tarif. Testen ist kostenlos: Ein Workspace ohne Tarif nimmt 50 Test-Einsendungen pro Monat von localhost an. Für den Livebetrieb wähle Pro ab 6 $/Monat für 500 Einsendungen oder zahle einmalig: 10.000 Einsendungen für 49 $ oder 50.000 Einsendungen für 149 $, mit Guthaben, das nie verfällt. Siehe Preise.

  1. Füge unter Allowed domains des Formulars die Domain deiner Site hinzu, plus localhost, während du entwickelst. Lass das Feld leer, um Posts von überall anzunehmen.
  2. Deaktiviere JavaScript in den Entwicklertools deines Browsers und sende das Formular ab. Es sollte trotzdem mit einem 303 auf deiner Dankeseite landen.
  3. Öffne mit aktiviertem JavaScript den Network-Tab und sende erneut. Der Request an /f/<formId> sollte mit 201 und JSON antworten, und die Seite sollte nicht neu laden.
  4. Sende mit einer zu kurzen Nachricht ab. Der einfache Post zeigt Ikiforms Fehlerseite mit deinem Feldlabel; die Skriptversion zeigt die Meldung unter dem Feld.
  5. Lade auf der Dankeseite neu. Nichts sollte erneut gesendet werden, und es sollte keine zweite Einsendung erscheinen.
  6. Öffne Submissions im Dashboard. Die neue Einsendung ist da, mit jedem Feld, das du gesendet hast.
  7. Sende einen Post mit ausgefülltem Honeypot, _gotcha=bot. Er bekommt trotzdem eine Erfolgsantwort, aber die Einsendung wird als Spam gespeichert und löst weder E-Mail noch Webhook aus.

Fehlerbehebung

ProblemWas zu tun ist
405 Method Not Allowed nach dem AbsendenDas Formular hat an deinen eigenen statischen Host gesendet, der kein POST annehmen kann. Prüfe action: Sie muss die vollständige URL https://ikiform.com/f/<formId> sein, kein relativer Pfad und nicht leer.
Den Endpunkt in einem Tab zu öffnen zeigt 404 not_foundErwartet. Ein Tab sendet GET, und der Endpunkt nimmt nur POST an. Prüfe, ob die method des Formulars post ist; ein Formular ohne method sendet GET mit den Feldern in der URL.
415 unsupported_media_typeDas Formular hat enctype="text/plain", oder ein Skript hat einen Typ gesendet, den Ikiform nicht liest. Entferne das enctype oder nutze multipart/form-data.
422 validation_failedDer Post passt nicht zur Felddefinition des Formulars. error.fields nennt jedes Feld und den Grund. Gleiche den name des Eingabefelds an die Feld-ID an.
Der Browser landet auf der Dankeseite von Ikiform statt auf deiner_redirect wird ignoriert, außer seine Domain steht unter Allowed domains und es ist eine https:-URL. Füge die Domain hinzu oder setze stattdessen Redirect after submit in den Einstellungen des Formulars.
Ein Feld fehlt in der EinsendungEs hat keinen name, ist disabled oder ist eine nicht angehakte Checkbox. Gib ihm einen name, nutze readonly statt disabled oder definiere ein checkbox-Feld, damit eine nicht angehakte Box als false gespeichert wird.
Neuladen fragt, ob das Formular erneut gesendet werden sollDie Seite hat den POST mit 200 beantwortet. Posts direkt an Ikiform bekommen immer einen 303; sitzt dein eigener Server dazwischen, leite nach der Verarbeitung des Posts weiter.
403 origin_not_allowed, oder jeder Post landet im SpamDie Domain der Seite steht nicht unter Allowed domains des Formulars. Füge sie hinzu, plus localhost für lokale Tests. Subdomains einer eingetragenen Domain sind erlaubt.

Fragen

Hängst du bei einem Schritt fest oder willst eine Anleitung für deinen Fall? Schreib an hello@ikiform.com.