Formulaire de contact sur un site statique7 min de lecture
Corriger l'erreur 405 d'un formulaire de contact hébergé sur Vercel
Une page statique sur Vercel répond à un POST de formulaire par 405 Method Not Allowed ; voici pourquoi, et comment envoyer le formulaire à un backend.
Vercel sert votre build statique sous forme de fichiers, et un POST vers un fichier reçoit 405 avec un corps vide, car aucune fonction ne gère ce chemin. Faites plutôt pointer l'action du formulaire vers votre endpoint Ikiform, ou écrivez une Vercel Function qui accepte l'envoi. Avec Ikiform, définissez l'id du formulaire par environnement Vercel, pour que les préproductions envoient vers un formulaire de test et la production vers le vrai.
Pourquoi Vercel répond 405
Vercel achemine chaque requête vers un fichier statique ou une fonction. Un site statique, un build Vite ou une app Next.js avec output: "export" n'a que des fichiers. Un GET sur /contact renvoie le fichier ; un POST vers le même chemin n'a nulle part où aller, Vercel le refuse donc avant que votre code ne puisse s'exécuter :
curl -i -X POST -d "message=hello" https://your-project.vercel.app/contactHTTP/2 405
server: Vercel
content-disposition: inline
x-vercel-cache: HIT
content-length: 0La réponse n'a pas de corps : le navigateur affiche une page blanche ou son propre écran d'erreur. Trois configurations mènent ici :
| Votre code | Pourquoi il renvoie 405 sur Vercel |
|---|---|
<form method="post"> sans action | Le formulaire envoie vers la page où il se trouve, qui est un fichier statique |
action="/api/contact" dans un projet Vite ou HTML simple | Il n'y a aucun fichier dans un dossier api/ à la racine du projet, donc aucune fonction pour ce chemin |
| Une Server Action ou un Route Handler Next.js dans un export statique | output: "export" ne prend pas en charge les Server Actions, ni les Route Handlers qui lisent la requête. next dev signale l'erreur, et le build n'a pas de serveur pour les exécuter |
- Le formulaire envoie vers un chemin de votre déploiement Vercel.
- Vercel cherche une fonction qui gère ce chemin.
- Si vous en avez écrit une, elle s'exécute. Dans un build statique, il n'y en a pas, Vercel répond donc 405 avec un corps vide.
- Avec l'action pointant vers Ikiform, l'envoi n'atteint jamais Vercel.
- Ikiform stocke le message, vous l'envoie par e-mail et redirige le navigateur vers une page statique de votre site Vercel.
Vous ajoutez donc une fonction, ou vous envoyez ailleurs. Une Vercel Function dans api/contact.ts fonctionne, mais il vous faut alors une API d'e-mail, un filtrage du spam et des limites de débit, et c'est vous qui les maintenez. Envoyer vers Ikiform garde le déploiement statique. La correction dans le HTML tient en un attribut :
<form method="post">
<input name="email" type="email" required />
<textarea name="message" required></textarea>
<button>Send</button>
</form><form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">Si vous préférez écrire la fonction
Une fonction est un choix raisonnable quand le message doit aller là où seul votre code peut accéder. Faites le compte de ce qu'elle demande avant de vous lancer :
- Un compte chez un fournisseur d'e-mail, un domaine d'envoi vérifié et une clé d'API dans les variables d'environnement de Vercel.
- Une validation côté serveur, car les attributs
requireddu navigateur sont une commodité, pas une vérification. - Un filtrage du spam et des limites de débit, sinon un formulaire de contact qui vous transmet chaque bot d'Internet.
- Un endroit où garder les messages quand le fournisseur d'e-mail est en panne, et un moyen de les renvoyer.
Un backend de formulaires couvre cette liste pour vous. Si vous voulez quand même votre code dans la boucle, laissez le formulaire envoyer à Ikiform et recevez un webhook signé dans une fonction ; votre propre serveur montre le gestionnaire.
Un id de formulaire par environnement Vercel
Chaque pull request sur Vercel a un déploiement de préproduction. Si les préproductions envoient vers votre formulaire de production, chaque message de test arrive dans votre boîte à côté des vrais. Créez un second formulaire Ikiform pour les préproductions, et laissez les variables d'environnement de Vercel choisir. Dans Settings › Environment Variables, ajoutez deux fois le même nom :
VITE_IKIFORM_FORM_ID Production frm_xxxxxxxxxxxxxxxx
VITE_IKIFORM_FORM_ID Preview frm_yyyyyyyyyyyyyyyyVite remplace au build les placeholders %NAME% d'index.html par les variables VITE_ : un formulaire HTML simple peut donc les utiliser sans JavaScript. VITE_VERCEL_ENV est défini par Vercel pour les projets Vite, et enregistre de quel déploiement vient un message :
<form id="contact" action="https://ikiform.com/f/%VITE_IKIFORM_FORM_ID%" method="post">
<label for="name">Name</label>
<input id="name" name="name" autocomplete="name" required />
<label for="email">Email</label>
<input id="email" name="email" type="email" autocomplete="email" required />
<label for="message">Message</label>
<textarea id="message" name="message" rows="6" minlength="10" required></textarea>
<input type="hidden" name="build" value="%VITE_VERCEL_ENV%" />
<input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
<button type="submit">Send message</button>
</form>- Pour un site statique, Vercel lit les variables d'environnement au build. Après en avoir changé une, redéployez, sinon l'ancienne valeur reste dans le HTML.
- Vite laisse un placeholder tel quel quand la variable n'existe pas : un id manquant est donc livré sous la forme
%VITE_IKIFORM_FORM_ID%et chaque envoi échoue avec400 Bad Requestavant d'atteindre le formulaire. La garde ci-dessous détecte ce cas. - L'id du formulaire est public dans tous les cas. Seules les variables
VITE_atteignent le navigateur, c'est pourquoi aucun secret ne doit s'y trouver.
const form = document.querySelector("#contact");
if (form && form.action.includes("%VITE_")) {
console.error("VITE_IKIFORM_FORM_ID is not set for this Vercel environment");
form.querySelector("button").disabled = true;
}Vous utilisez Next.js avec output: "export" ? Lisez plutôt process.env.NEXT_PUBLIC_IKIFORM_FORM_ID dans un composant client ; le guide principal contient un formulaire en export statique. Si votre app Next.js tourne bien sur les serveurs de Vercel, une Server Action peut envoyer avec une clé secrète : voir le guide Next.js.
En-têtes et URL propres
Si votre site définit une Content-Security-Policy, définissez-la dans vercel.json en incluant Ikiform. cleanUrls sert thanks.html à l'adresse /thanks, ce qui donne une cible de redirection plus propre :
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"cleanUrls": true,
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Content-Security-Policy",
"value": "default-src 'self'; form-action 'self' https://ikiform.com; connect-src 'self' https://ikiform.com"
}
]
}
]
}Préproductions et domaines autorisés
Les URL de préproduction comme your-project-git-branch-team.vercel.app ne sont pas des sous-domaines de your-project.vercel.app, elles ne correspondent donc pas dans Allowed domains. Leurs envois finissent en spam avec origin_mismatch. Raison de plus pour un formulaire de préproduction séparé : laissez ses domaines autorisés vides, ou ajoutez l'hôte de préproduction que vous testez.
localhost : ils comptent dans votre offre comme toute soumission réelle.Vérifiez que tout fonctionne
- Lancez le
curlci-dessus sur votre URL de production avant la correction, et constatez le405. Après la correction, l'actiondu formulaire dans le HTML déployé commence parhttps://ikiform.com/f/. - Ouvrez un déploiement de préproduction, envoyez, et vérifiez que le message arrive dans le formulaire de préproduction, pas dans celui de production.
- Envoyez depuis votre domaine de production et vérifiez que le champ
buildvautproduction. - Vérifiez la boîte de réception de chaque destinataire des notifications. Chacun reçoit un e-mail avec les champs, et Reply répond à l'expéditeur quand le formulaire a un champ
email. - Rien n'est arrivé ? Passez le filtre de statut du tableau de bord sur Spam. Le spam reçoit la même réponse de succès qu'une vraie soumission.
Pièges
| Problème | Que faire |
|---|---|
Toujours 405 après avoir modifié le formulaire | Le déploiement que vous testez a été construit avant la modification, ou un gestionnaire JavaScript envoie vers votre propre chemin avec fetch. Cherchez /api/contact dans les fichiers compilés. |
400 Bad Request à chaque envoi, ou 404 not_found de la part d'Ikiform | L'id du formulaire n'a pas atteint le build, ou ce n'est pas le bon id pour cet environnement. Vérifiez que la variable existe pour cet environnement et redéployez. |
| Les préproductions fonctionnent, les envois de production finissent en spam | Votre domaine de production manque dans les Allowed domains du formulaire de production. Ajoutez le domaine personnalisé en plus de your-project.vercel.app. |
| Le navigateur arrive sur la page de remerciement d'Ikiform au lieu de la vôtre | _redirect est ignoré sauf si son domaine figure dans Allowed domains et qu'il s'agit d'une URL https:. Ajoutez le domaine, ou définissez plutôt Redirect after submit dans les réglages du formulaire. |
Questions
Le formulaire envoie vers un chemin qui n'a qu'un fichier statique. Vercel sert les fichiers pour les requêtes GET, et sans fonction pour ce chemin, il refuse le POST avec 405. Envoyez le formulaire vers un backend de formulaires ou ajoutez une Vercel Function.
Non. Les Server Actions ne sont pas prises en charge avec output : export, car il n'y a pas de serveur pour les exécuter. Envoyez depuis un composant client vers un backend de formulaires, ou déployez sans export statique pour que Vercel exécute l'action.
Mieux vaut pas. Donnez aux préproductions leur propre id de formulaire via une variable d'environnement Preview, pour que les messages de test n'atteignent ni votre boîte ni vos webhooks.
Non. Le formulaire fonctionne sans. N'ajoutez vercel.json que pour définir une Content-Security-Policy qui autorise ikiform.com, ou pour activer cleanUrls et obtenir une URL de remerciement plus propre.
Non, il n'y a pas d'offre gratuite. Les tests sont gratuits : vous pouvez envoyer 50 soumissions de test par mois depuis localhost avant de payer. Pour passer en production, Pro commence à 6 $/mois pour 500 soumissions, ou vous pouvez payer une seule fois 10 000 soumissions pour 49 $ ou 50 000 soumissions pour 149 $, avec des crédits qui n'expirent jamais.
Une étape vous bloque, ou vous voulez un guide pour votre cas ? Écrivez à hello@ikiform.com.