仕組み
送信データが通過するすべてのチェックを順番に、それぞれが返しうる応答とあわせて説明します。
/f/<formId> への送信は、すべて同じパイプラインを通ります。コストの低いチェックから先に実行するので、大量送信や存在しないフォームへの送信にはほとんどコストがかかりません。最初に失敗したチェックが応答を決めます。
ボディを読む前
- 1大量送信ガードIP ごとに 1 分あたり 600 件、全フォーム合計429 rate_limited
- 2フォームの検索存在しない、削除済み、無効なフォーム404 not_found
- 3フォームのレート制限フォームのプリセット。訪問者ごととフォームごと429 rate_limited
- 4一時停止ダッシュボードでフォームが一時停止されている403 form_paused
送信を読み取る
- 5解析urlencoded、multipart、JSON、UTF-8、サイズ上限400、413、415、422
- 6API キーAuthorization ヘッダーが送られた場合のみ403 forbidden
- 7許可ドメインOrigin または Referer をフォームのドメインと照合スパム、または 403
- 8人間確認確認がオンの場合の Turnstile トークン403、または確認ページ
判定する
- 9バリデーション公開済みのフィールドがあれば、それと照合422 validation_failed
- 10スコアハニーポット、時間、リンク、キーワード、重複5 以上でスパム
- 11冪等性同じキーなら最初の応答を再送再送、409、422
- 12月間の使用量ワークスペースの上限を大きく超えている429 quota_exceeded
保存
送信データを保存
コードには 201、ブラウザーには 303
- Webhook署名付き、約 3 日間リトライ
- 通知メールフォームの受信者へ
- ダッシュボードと APIすぐにリアルタイムで反映
スパムも保存され、成功と同じ応答を返しますが、何も送信されません。
各ステージの役割
何よりも先にレート制限
レート制限はボディを読む前に実行されます。大量送信ガード(IP ごとに 1 分あたり 600 件)はフォームの検索よりも前に動くので、大量送信がデータベースに届くことはありません。フォーム独自のルールは検索の直後に実行されます。拒否されたリクエストは許容量を消費しません。正確な数値はレート制限にあります。
解析
ボディは urlencoded、multipart、JSON として解析されます。テキストは UTF-8 としてデコードされ、NFC に正規化され、CRLF は LF に変換され、制御文字は削除されます。_ で始まる名前は _redirect や _subject などの予約済みの指示で、回答として保存されることはありません。HTML フォームを参照してください。
送信元の判定
Authorization: Bearer ヘッダーは任意です。submissions:write スコープを持つシークレットキー(ik_sk_)は、許可ドメインのチェックと Ikiform の人間確認をスキップします。公開可能キー(ik_pub_)は、キーに登録されたドメインからのみ使えます。キーがない場合は、Origin で送信を判定します。
スパム
スパムがエラーになることはありません。スパムモードで許可ドメインのポリシーに違反した送信や、スコアが 5 以上の送信は、ステータス spam で保存され、本物の送信と同じ成功の応答を返すので、ボットは何も学べません。スパムは Webhook もメールも送らず、使用量にもカウントされません。スパム対策を参照してください。
保存と配信
送信データ、その Webhook の配信、通知メールは 1 回のデータベースバッチで書き込まれ、キューに渡されます。Webhook の配信やメールが応答を遅くすることはなく、配信なしで送信データだけが保存されることもありません。
JSON かリダイレクトか
同じエンドポイントが、ブラウザーにはページで、コードには JSON で応答します。Ikiform はリクエストごとに判断します:
- 1Accept に application/json が含まれるJSON
- 2ボディが JSONJSON
- 3Sec-Fetch-Mode: navigateリダイレクトまたはページ
- 4それ以外の Sec-Fetch-Mode(cors など)JSON
- 5Sec-Fetch-Mode がなく、Accept に text/html が含まれるリダイレクトまたはページ
- 6それ以外すべて(curl など)JSON
最初に一致したルールが適用されます。
JSON モードでは、成功すると 201 { "ok": true, "id": "sub_..." } を返します。ページモードでは成功すると 303 リダイレクトになり、エラー時はフィールドの問題をラベルごとに一覧にした、ホストされたエラーページを表示します。
送信データの保存後
ID
| ID | 形式 | メモ |
|---|---|---|
| フォーム | frm_xxxxxxxxxxxxxxxx | frm_ に続くランダムな 16 文字。公開情報で、フォームの action の URL に含まれます。 |
| 送信データ | sub_01k7v2c9t3e8m5q4x6z0a1b2c3 | sub_ に続く 26 文字で、時刻順に並びます。 |
| Webhook の配信 | dlv_... | webhook-id として送られ、リトライしても変わりません。 |
| リクエスト | req_... | すべてのレスポンスに X-Request-Id ヘッダーが付きます。サポートに問い合わせるときに伝えてください。 |
{ "ok": true, "id": "sub_01k7v2c9t3e8m5q4x6z0a1b2c3" }