Formulario de contacto en un sitio estático

Formulario de contacto en un sitio estático6 min de lectura

Añade un formulario de contacto a un sitio web estático en Amazon S3

Los website endpoints de S3 solo aceptan GET y HEAD por HTTP plano, así que envía el formulario de contacto a un backend y configura bien las redirecciones con CloudFront.

Preet SutharFundador, Ikiform

Un website endpoint de S3 responde al POST de un formulario con 405 MethodNotAllowed, así que apunta el action del formulario a tu endpoint de Ikiform. Como el endpoint es http: plano, un _redirect de vuelta a él nunca se sigue; configura Redirect after submit en los ajustes del formulario, o pon CloudFront delante para tener https:. Con CloudFront delante del endpoint REST del bucket, redirige a un nombre de archivo completo como thanks.html, porque el default root object solo se aplica a la raíz.

Qué cambia en S3

Un bucket configurado para alojar un sitio web estático tiene su propio website endpoint, como http://www.example.com.s3-website-us-east-1.amazonaws.com. AWS documenta que solo admite peticiones GET y HEAD sobre objetos. El envío de un formulario recibe una página de error HTML:

Respuesta a un 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>

Otros tres rasgos de S3 condicionan el formulario de contacto:

Rasgo de S3Qué significa para el formulario
Los website endpoints no admiten HTTPSIkiform solo sigue un _redirect a una URL https:, así que se ignora una redirección de vuelta al endpoint sin más
Las cabeceras de respuesta vienen de CloudFront, no del bucketLa Content-Security-Policy se define en una política de cabeceras de respuesta de CloudFront
El default root object de CloudFront solo se aplica a la raízCon un origen REST, https://example.com/thanks/ no carga thanks/index.html; redirige a thanks.html

Para un sitio https:, AWS recomienda Amplify Hosting, que funciona sobre CloudFront, o CloudFront delante del bucket. El formulario funciona en ambos casos. Lo que cambia es dónde acaba el visitante después de enviar.

Dónde acaba el visitante después de enviar, con y sin CloudFrontwebsite endpoint de S3, httpCloudFront y tu dominio, httpshttp://…s3-website…contact.htmlIkiformguarda, te avisaPágina de graciasde Ikiform_redirect a httpignoradohttps://www.example.comcontact.htmlIkiformguarda, te avisatu thanks.html_redirect seguidoPOST303POST303Dónde acaba el visitante después de enviar, con y sin CloudFrontwebsite endpoint de S3, httpCloudFront y tu dominio, httpshttp://…s3-website…contact.htmlIkiformguarda, te avisaPágina de gracias deIkiform_redirect a http ignoradohttps://www.example.comcontact.htmlIkiformguarda, te avisatu thanks.html_redirect seguidoPOST303POST303
  1. En el website endpoint sin más, la página se sirve por http y envía a Ikiform.
  2. Ikiform guarda el mensaje, pero ignora un _redirect a una dirección http y muestra su página de agradecimiento alojada.
  3. Configurar Redirect after submit en el panel es la forma de evitarlo, porque acepta URL http.
  4. Detrás de CloudFront con tu propio dominio, la página es https.
  5. Ikiform sigue el _redirect a tu thanks.html, siempre que el dominio esté en Allowed domains.
El mensaje se guarda en ambos casos. Solo el último paso, a dónde va el navegador, depende de https.

Qué origen de CloudFront usar

CloudFront puede leer del bucket de dos formas, y la elección decide cómo debe ser tu URL de agradecimiento:

OrigenBucketPáginas índice de carpetasURL de agradecimiento
El website endpoint de S3, como origen personalizadoDebe ser de lectura públicaFuncionan: /thanks/ carga thanks/index.html/thanks/ o /thanks.html
El endpoint REST, con origin access controlSigue siendo privado, solo lo lee CloudFrontSolo la raíz, mediante el default root object/thanks.html, un nombre de archivo completo

Un nombre de archivo completo funciona con ambos, y por eso los ejemplos lo usan. Si prefieres no gestionar CloudFront tú, Amplify Hosting puede desplegar desde el bucket con https: y una CDN gestionada; ahí el formulario tampoco necesita cambios.

El formulario

Los sitios en S3 suelen ser sitios de empresa, así que este formulario pide un email de trabajo y el nombre de la empresa. Súbelo como contact.html junto a 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>
  • El _redirect apunta al dominio de CloudFront, con un nombre de archivo. Solo se sigue cuando www.example.com o example.com está en Allowed domains.
  • En el endpoint http: sin más, quita el input _redirect y configura Redirect after submit con la página de agradecimiento. Ese ajuste acepta URL http:, porque solo tu equipo puede cambiarlo.
  • Mantén email como nombre del campo. Los emails de notificación lo usan como dirección de respuesta.

En un sitio de empresa, normalmente más de una persona lee la bandeja de contacto. Añade hasta 10 destinatarios de notificaciones confirmados al formulario; cada uno recibe el mensaje, y quien pulse Reply responde directamente al remitente. Si los mensajes también deben llegar a un canal compartido o a una cola de tickets, añade un webhook firmado y pásalo por Zapier o por tu propio código. El campo company llega como texto plano, listo para filtrar en cualquiera de los dos sitios.

Antes de subirlo, prueba la página desde un servidor local con localhost en Allowed domains. Los envíos desde localhost cuentan como pruebas, así que puedes dejar el formulario bien antes de que el bucket llegue a servirlo.

Sincroniza la carpeta con el bucket e invalida las páginas en CloudFront para que el nuevo formulario se sirva de inmediato:

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

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

Dominios permitidos en hosts de AWS

Dónde se sirve la páginaAñade
Website endpoint sin másEl host completo del endpoint del bucket, como www.example.com.s3-website-us-east-1.amazonaws.com
Dominio por defecto de CloudFrontEl host exacto d111111abcdef8.cloudfront.net, mientras pruebas
Tu propio dominioexample.com, que también cubre www.example.com

Nunca añadas amazonaws.com, un sufijo regional s3-website o cloudfront.net por sí solos. Coincidiría cualquier bucket o distribución del mundo. AWS registra los dominios de los website endpoints de S3 en la Public Suffix List por la misma razón: cada bucket es un sitio distinto.

Cabeceras a través de CloudFront

Los metadatos de objeto de S3 no pueden definir una Content-Security-Policy, así que defínela en una política de cabeceras de respuesta de CloudFront y asóciala al comportamiento de caché por defecto de la distribución. El valor de la cabecera está 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 sustituye cualquier CSP que envíe el origen. Con un origen S3 sin más no hay ninguna, pero así la política sigue mandando si cambias de origen más adelante.

Comprueba que funciona

  1. Añade los dominios de la tabla de arriba, más localhost mientras pruebas.
  2. Envía desde tu dominio de CloudFront. Deberías llegar a thanks.html en tu propio dominio.
  3. Si también mantienes público el website endpoint sin más, envía desde él y confirma que llegas a la página configurada en Redirect after submit.
  4. Abre Submissions en el panel. El nuevo envío está ahí con todos los campos que enviaste.
  5. Revisa la bandeja de entrada de cada destinatario de notificaciones. Cada uno recibe un email con los campos, y Reply va a quien envió el formulario cuando este tiene un campo email.
  6. ¿No llegó nada? Cambia el filtro de estado del panel a Spam. El spam recibe la misma respuesta de éxito que un envío real.

Problemas habituales

ProblemaQué hacer
405 Method Not Allowed con Code: MethodNotAllowedEl formulario envió al bucket. Puede que CloudFront aún sirva el contact.html antiguo; invalídalo.
AccessDenied o 403 después de la redirecciónLa redirección apunta a una carpeta como /thanks/ en una distribución de CloudFront con origen REST. Apúntala a thanks.html.
El navegador llega a la página de agradecimiento de Ikiform en lugar de a la tuya_redirect se ignora salvo que su dominio esté en Allowed domains y sea una URL https:. Añade el dominio, o configura Redirect after submit en los ajustes del formulario.
403 origin_not_allowed, o todos los envíos acaban en spamEl dominio de la página no está en Allowed domains del formulario. Añádelo, más localhost para las pruebas locales. Los subdominios de un dominio de la lista están permitidos.

Preguntas

¿Te atascaste en un paso o quieres una guía para tu caso? Escribe a hello@ikiform.com.