静的サイトのお問い合わせフォーム2 分で読めます
Amazon S3 の静的ウェブサイトにお問い合わせフォームを追加する
S3 のウェブサイトエンドポイントは平文 HTTP の GET と HEAD しか受け付けません。お問い合わせフォームはフォームバックエンドに送信し、リダイレクトは CloudFront で正しく扱います。
S3 のウェブサイトエンドポイントはフォームの POST に 405 MethodNotAllowed を返すので、フォームの action は Ikiform のエンドポイントに向けます。エンドポイントは平文の http: なので、そこへ戻る _redirect はたどられません。フォーム設定の Redirect after submit を設定するか、https: のために CloudFront を前段に置いてください。バケットの REST エンドポイントの前に CloudFront を置く場合、デフォルトルートオブジェクトはルートにしか適用されないので、thanks.html のような完全なファイル名にリダイレクトします。
S3 ならではの違い
静的ウェブサイトホスティングを設定したバケットには、http://www.example.com.s3-website-us-east-1.amazonaws.com のような専用のウェブサイトエンドポイントが付きます。AWS のドキュメントによると、オブジェクトに対しては GET と HEAD リクエストしかサポートしていません。フォームを送信すると HTML のエラーページが返ります:
<html>
<head><title>405 Method Not Allowed</title></head>
<body>
<h1>405 Method Not Allowed</h1>
<ul>
<li>Code: MethodNotAllowed</li>
<li>Message: The specified method is not allowed against this resource.</li>
<li>Method: POST</li>
<li>ResourceType: OBJECT</li>お問い合わせフォームに影響する S3 の特徴があと 3 つあります:
| S3 の特徴 | フォームへの影響 |
|---|---|
| ウェブサイトエンドポイントは HTTPS をサポートしない | Ikiform は https: の URL への _redirect しかたどらないので、素のエンドポイントへ戻るリダイレクトは無視される |
| レスポンスヘッダーはバケットではなく CloudFront が付ける | Content-Security-Policy は CloudFront のレスポンスヘッダーポリシーで設定する |
| CloudFront のデフォルトルートオブジェクトはルートにしか適用されない | REST オリジンでは https://example.com/thanks/ で thanks/index.html は読み込まれない。thanks.html にリダイレクトする |
https: のサイトには、CloudFront 上で動く Amplify Hosting か、バケットの前に CloudFront を置く構成を AWS は推奨しています。フォームはどちらでも動きます。変わるのは、送信後に訪問者がたどり着く場所です。
- 素のウェブサイトエンドポイントでは、ページは http で配信され、Ikiform に送信します。
- Ikiform はメッセージを保存しますが、http のアドレスへの _redirect は無視し、ホストされたサンクスページを表示します。
- ダッシュボードで Redirect after submit を設定すれば回避できます。こちらは http の URL も受け付けるからです。
- 独自ドメインで CloudFront の背後に置けば、ページは https になります。
- ドメインが Allowed domains にあれば、Ikiform は _redirect に従って thanks.html に移動させます。
どの CloudFront オリジンを使うか
CloudFront がバケットを読む方法は 2 つあり、どちらを選ぶかでサンクスページの URL の形が決まります:
| オリジン | バケット | フォルダーのインデックスページ | サンクスページの URL |
|---|---|---|---|
| S3 ウェブサイトエンドポイントをカスタムオリジンとして | 公開読み取りが必要 | 使える。/thanks/ で thanks/index.html が読み込まれる | /thanks/ または /thanks.html |
| REST エンドポイントとオリジンアクセスコントロール | 非公開のまま、CloudFront だけが読み取る | ルートのみ。デフォルトルートオブジェクトで | /thanks.html のように完全なファイル名 |
完全なファイル名ならどちらでも使えるので、サンプルではそうしています。CloudFront を自分で運用したくなければ、Amplify Hosting で https: とマネージド CDN 付きでバケットからデプロイできます。その場合もフォームの変更は不要です。
フォーム
S3 のサイトは企業サイトであることが多いので、このフォームでは仕事用のメールアドレスと会社名を尋ねます。thanks.html と同じ場所に contact.html としてアップロードします:
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
<label for="name">Name</label>
<input id="name" name="name" autocomplete="name" required />
<label for="email">Work email</label>
<input id="email" name="email" type="email" autocomplete="email" required />
<label for="company">Company</label>
<input id="company" name="company" autocomplete="organization" />
<label for="message">How can we help?</label>
<textarea id="message" name="message" rows="6" minlength="10" required></textarea>
<input type="hidden" name="_redirect" value="https://www.example.com/thanks.html" />
<input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
<button type="submit">Send</button>
</form>_redirectはファイル名付きで CloudFront のドメインを指しています。www.example.comかexample.comが Allowed domains にある場合にだけ従います。- 素の
http:エンドポイントでは、_redirectの入力欄を削除し、代わりに Redirect after submit をサンクスページに設定します。この設定は自分のチームしか変更できないので、http:の URL も受け付けます。 - フィールド名は
emailのままにしてください。通知メールはこれを reply-to アドレスとして使います。
企業サイトでは、問い合わせの受信トレイを複数人で読むのが普通です。確認済みの通知先をフォームに最大 10 件まで追加すると、全員にメッセージが届き、Reply を押した人が送信者に直接返信できます。共有チャンネルやチケットのキューにも届けたい場合は、署名付き Webhook を追加し、Zapier や自分のコードで振り分けてください。company フィールドはプレーンテキストで届くので、どちらでもそのまま絞り込みに使えます。
アップロードの前に、localhost を Allowed domains に入れてローカルサーバーでページをテストします。localhost からの送信はテストとして扱われるので、バケットで配信する前にフォームを仕上げられます。
フォルダーをバケットに同期し、CloudFront でページを無効化して、新しいフォームがすぐに配信されるようにします:
aws s3 sync ./site s3://www.example.com --delete
aws cloudfront create-invalidation --distribution-id E1EXAMPLE --paths "/contact.html" "/thanks.html"AWS のホストでの許可ドメイン
| ページの配信元 | 追加するもの |
|---|---|
| 素のウェブサイトエンドポイント | www.example.com.s3-website-us-east-1.amazonaws.com のような、バケットのエンドポイントのホスト全体 |
| CloudFront のデフォルトドメイン | テスト中は d111111abcdef8.cloudfront.net のホストそのもの |
| 独自ドメイン | example.com。www.example.com もカバーする |
amazonaws.com、リージョンごとの s3-website のサフィックス、cloudfront.net だけを追加してはいけません。世界中のすべてのバケットやディストリビューションが一致してしまいます。AWS が S3 ウェブサイトエンドポイントのドメインを Public Suffix List に登録しているのも同じ理由で、バケットはそれぞれ別のサイトだからです。
CloudFront でヘッダーを付ける
S3 のオブジェクトメタデータでは Content-Security-Policy を設定できないので、CloudFront のレスポンスヘッダーポリシーで設定し、ディストリビューションのデフォルトキャッシュ動作に関連付けます。ヘッダーの値は 1,783 文字までです:
{
"Name": "site-csp",
"SecurityHeadersConfig": {
"ContentSecurityPolicy": {
"Override": true,
"ContentSecurityPolicy": "default-src 'self'; form-action 'self' https://ikiform.com; connect-src 'self' https://ikiform.com"
}
}
}aws cloudfront create-response-headers-policy --response-headers-policy-config file://csp-policy.jsonOverride: true は、オリジンが送る CSP を置き換えます。素の S3 オリジンには CSP はありませんが、後でオリジンを変えてもこのポリシーが優先されるようになります。動作を確認する
- 上の表のドメインと、テスト中は
localhostを追加します。 - CloudFront のドメインから送信します。独自ドメインの
thanks.htmlに移動するはずです。 - 素のウェブサイトエンドポイントも公開したままにする場合は、そこから送信し、Redirect after submit で設定したページに移動することを確認します。
- ダッシュボードで Submissions を開きます。送ったすべてのフィールドを含む新しい送信データがあります。
- 通知の受信者それぞれの受信トレイを確認します。各自にフィールド入りのメールが届き、フォームに
emailフィールドがあれば Reply の宛先は送信者になります。 - 何も届かない場合は、ダッシュボードのステータスフィルターを Spam に切り替えてください。スパムにも本物の送信と同じ成功の応答が返ります。
ハマりどころ
| 問題 | 対処 |
|---|---|
Code: MethodNotAllowed 付きの 405 Method Not Allowed | フォームがバケットに送信されています。CloudFront がまだ古い contact.html を配信しているかもしれないので、無効化してください。 |
リダイレクト後に AccessDenied や 403 になる | REST オリジンの CloudFront ディストリビューションで、リダイレクト先が /thanks/ のようなフォルダーになっています。thanks.html を指定してください。 |
| 自分のページではなく Ikiform のサンクスページに移動する | _redirect は、ドメインが Allowed domains にあり、かつ https: の URL でない限り無視されます。ドメインを追加するか、代わりにフォーム設定で Redirect after submit を設定してください。 |
403 origin_not_allowed が返るか、すべての送信がスパムになる | ページのドメインがフォームの Allowed domains にありません。ドメインと、ローカルのテスト用に localhost を追加してください。登録済みドメインのサブドメインは許可されます。 |
よくある質問
いいえ。S3 のウェブサイトエンドポイントは GET と HEAD リクエストしかサポートしないので、POST には 405 MethodNotAllowed が返ります。フォームの送信先をフォームバックエンドにするか、Lambda で API を作ってください。
いいえ。http のページからでもフォームは Ikiform に送信されます。CloudFront で https にすると、Ikiform が _redirect に従って自分のサンクスページに戻せるようになります。
その構成でも動き、すべてを AWS 内に収められますが、バリデーション、スパムフィルタリング、保存、リトライを自分で作る必要があり、SES には認証済みの送信者が必要です。お問い合わせフォームなら、フォームバックエンドのほうが保守の手間が少なくて済みます。
キャッシュが期限切れになるまでは、その可能性があります。変更のたびに contact.html を無効化するか、Cache-Control の max-age を短くして HTML をアップロードすれば、新しいフォームがすぐに反映されます。
いいえ、無料プランはありません。テストは無料で、支払いの前に localhost から月 50 件のテスト送信ができます。本番運用するには、月 $6 で 500 件からの Pro を選ぶか、1 回払いで 10,000 件 $49 または 50,000 件 $149 を購入できます。クレジットに有効期限はありません。
手順で詰まったときや、あなたの状況に合うガイドがほしいときはメールでどうぞ: hello@ikiform.com