Formulário de contato em site estático

Formulário de contato em site estático6 min de leitura

Adicione um formulário de contato a um site estático no Amazon S3

Endpoints de site do S3 só aceitam GET e HEAD via HTTP simples, então envie o formulário de contato para um backend de formulários e acerte os redirecionamentos com o CloudFront.

Preet SutharFundador, Ikiform

Um endpoint de site do S3 responde a um POST de formulário com 405 MethodNotAllowed, então aponte o action do formulário para o seu endpoint do Ikiform. Como o endpoint é http: simples, um _redirect de volta para ele nunca é seguido; defina Redirect after submit nas configurações do formulário, ou coloque o CloudFront na frente para ter https:. Com o CloudFront na frente do endpoint REST do bucket, redirecione para um nome de arquivo completo, como thanks.html, porque o default root object só vale para a raiz.

O que muda no S3

Um bucket configurado para hospedagem de site estático ganha o próprio endpoint de site, como http://www.example.com.s3-website-us-east-1.amazonaws.com. A AWS documenta que ele só suporta requisições GET e HEAD em objetos. Um envio de formulário recebe uma página de erro em HTML:

Resposta a um POST
<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>

Mais três características do S3 influenciam o formulário de contato:

Característica do S3O que significa para o formulário
Endpoints de site não suportam HTTPSO Ikiform só segue um _redirect para uma URL https:, então um redirecionamento de volta para o endpoint puro é ignorado
Os headers de resposta vêm do CloudFront, não do bucketUma Content-Security-Policy é definida numa response headers policy do CloudFront
O default root object do CloudFront só vale para a raizCom uma origem REST, https://example.com/thanks/ não carrega thanks/index.html; redirecione para thanks.html

Para um site https:, a AWS recomenda o Amplify Hosting, que roda no CloudFront, ou o CloudFront na frente do bucket. O formulário funciona dos dois jeitos. O que muda é onde o visitante vai parar depois de enviar.

Onde o visitante cai depois de enviar, com e sem CloudFrontendpoint de site S3 puro, httpCloudFront e seu domínio, httpshttp://…s3-website…contact.htmlIkiformarmazena, avisa vocêPágina deagradecimento doIkiform_redirect para httpignoradohttps://www.example.comcontact.htmlIkiformarmazena, avisa vocêseu thanks.html_redirect seguidoPOST303POST303Onde o visitante cai depois de enviar, com e sem CloudFrontendpoint de site S3 puro, httpCloudFront e seu domínio, httpshttp://…s3-website…contact.htmlIkiformarmazena, avisa vocêPágina de agradecimentodo Ikiform_redirect para http ignoradohttps://www.example.comcontact.htmlIkiformarmazena, avisa vocêseu thanks.html_redirect seguidoPOST303POST303
  1. No endpoint de site puro, a página é servida via http e envia ao Ikiform.
  2. O Ikiform armazena a mensagem, mas ignora um _redirect para um endereço http e mostra a página de agradecimento hospedada.
  3. Definir Redirect after submit no painel é o jeito de contornar isso, porque essa configuração aceita URLs http.
  4. Atrás do CloudFront com o seu próprio domínio, a página é https.
  5. O Ikiform segue o _redirect para o seu thanks.html, desde que o domínio esteja em Allowed domains.
A mensagem é armazenada de qualquer jeito. Só o último passo, para onde o navegador vai, depende de https.

Qual origem do CloudFront

O CloudFront pode ler do bucket de duas formas, e a escolha decide como deve ser a sua URL de agradecimento:

OrigemBucketPáginas index de pastasURL de agradecimento
O endpoint de site do S3, como origem personalizadaPrecisa ter leitura públicaFuncionam: /thanks/ carrega thanks/index.html/thanks/ ou /thanks.html
O endpoint REST, com origin access controlContinua privado, lido só pelo CloudFrontSó na raiz, pelo default root object/thanks.html, um nome de arquivo completo

Um nome de arquivo completo funciona com as duas, e é por isso que os exemplos usam um. Se você prefere não administrar o CloudFront, o Amplify Hosting pode fazer o deploy a partir do bucket com https: e uma CDN gerenciada; o formulário também não precisa de mudança lá.

O formulário

Sites no S3 costumam ser sites de empresas, então este formulário pede um e-mail de trabalho e o nome da empresa. Envie-o como contact.html ao lado de 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>
  • O _redirect aponta para o domínio do CloudFront, com um nome de arquivo. Ele só é seguido quando www.example.com ou example.com está em Allowed domains.
  • No endpoint http: puro, remova o input _redirect e defina Redirect after submit com a página de agradecimento. Essa configuração aceita URLs http:, porque só a sua equipe pode mudá-la.
  • Mantenha email como nome do campo. Os e-mails de notificação o usam como endereço de reply-to.

Num site de empresa, geralmente mais de uma pessoa lê a caixa de entrada de contato. Adicione até 10 destinatários de notificação confirmados ao formulário; cada um recebe a mensagem, e quem clicar em Reply responde direto ao remetente. Se as mensagens também devem chegar a um canal compartilhado ou a uma fila de tickets, adicione um webhook assinado e direcione-o pelo Zapier ou pelo seu próprio código. O campo company chega como texto simples, então já está pronto para filtrar em qualquer um dos dois lugares.

Antes de subir, teste a página a partir de um servidor local com localhost em Allowed domains. Envios de localhost contam como testes, então você pode acertar o formulário antes de o bucket servi-lo.

Sincronize a pasta com o bucket e invalide as páginas no CloudFront para o novo formulário ser servido na hora:

Terminal
aws s3 sync ./site s3://www.example.com --delete

aws cloudfront create-invalidation --distribution-id E1EXAMPLE --paths "/contact.html" "/thanks.html"

Domínios permitidos em hosts da AWS

Onde a página é servidaAdicione
Endpoint de site puroO host completo do endpoint do bucket, como www.example.com.s3-website-us-east-1.amazonaws.com
Domínio padrão do CloudFrontO host exato d111111abcdef8.cloudfront.net, enquanto você testa
Seu próprio domínioexample.com, que também cobre www.example.com

Nunca adicione amazonaws.com, um sufixo regional s3-website ou cloudfront.net sozinhos. Todo bucket ou distribuição do mundo passaria a corresponder. A AWS registra os domínios de endpoint de site do S3 na Public Suffix List pelo mesmo motivo: cada bucket é um site separado.

Headers pelo CloudFront

Os metadados de objetos do S3 não conseguem definir uma Content-Security-Policy, então defina-a numa response headers policy do CloudFront e anexe-a ao default cache behavior da distribuição. O valor do header é limitado a 1.783 caracteres:

csp-policy.json
{
  "Name": "site-csp",
  "SecurityHeadersConfig": {
    "ContentSecurityPolicy": {
      "Override": true,
      "ContentSecurityPolicy": "default-src 'self'; form-action 'self' https://ikiform.com; connect-src 'self' https://ikiform.com"
    }
  }
}
Terminal
aws cloudfront create-response-headers-policy --response-headers-policy-config file://csp-policy.json
Override: true substitui qualquer CSP que a origem envie. Com uma origem S3 pura não existe nenhuma, mas isso mantém a policy no controle se você trocar de origem depois.

Confira se funciona

  1. Adicione os domínios da tabela acima, mais localhost enquanto testa.
  2. Envie a partir do seu domínio do CloudFront. Você deve cair em thanks.html no seu próprio domínio.
  3. Se você também mantém o endpoint de site puro público, envie a partir dele e confirme que chega à página definida em Redirect after submit.
  4. Abra Submissions no painel. O novo envio está lá com todos os campos que você enviou.
  5. Confira a caixa de entrada de cada destinatário das notificações. Cada um recebe um e-mail com os campos, e Reply vai para quem enviou quando o formulário tem um campo email.
  6. Não chegou nada? Mude o filtro de status do painel para Spam. Spam recebe a mesma resposta de sucesso de um envio real.

Pegadinhas

ProblemaO que fazer
405 Method Not Allowed com Code: MethodNotAllowedO formulário enviou para o bucket. O CloudFront ainda pode estar servindo o contact.html antigo; invalide-o.
AccessDenied ou 403 depois do redirecionamentoO redirecionamento aponta para uma pasta como /thanks/ numa distribuição do CloudFront com origem REST. Aponte para thanks.html.
O navegador cai na página de agradecimento do Ikiform em vez da suaO _redirect é ignorado, a menos que o domínio dele esteja em Allowed domains e ele seja uma URL https:. Adicione o domínio, ou defina Redirect after submit nas configurações do formulário.
403 origin_not_allowed, ou todo envio cai no spamO domínio da página não está em Allowed domains do formulário. Adicione-o, mais localhost para testes locais. Subdomínios de um domínio listado são permitidos.

Perguntas

Travou em algum passo ou quer um guia para o seu caso? Envie um e-mail para hello@ikiform.com.