Empêcher une nouvelle soumission de formulaire

107

La première page contient un formulaire HTML. Page deux - le code qui gère les données soumises.

Le formulaire de la première page est soumis. Le navigateur est redirigé vers la page deux. La page deux gère les données soumises.

À ce stade, si la page deux est actualisée, une alerte "Confirmer la nouvelle soumission du formulaire" apparaît.

Cela peut-il être évité?

Emanuil Rusev
la source
Utilisez une boîte de dialogue de confirmation: stackoverflow.com/questions/6457750/form-confirm-before-submit/…
3
utiliser la redirection de poste comme décrit ici - >> en.wikipedia.org/wiki/Post/Redirect/Get
Meer
Vous pouvez empêcher cela même sans redirection. Regardez ici
Eugen Konkov

Réponses:

145

Il y a 2 approches que les gens utilisaient ici:

Méthode 1: utiliser AJAX + Redirect

De cette façon, vous publiez votre formulaire en arrière-plan en utilisant JQuery ou quelque chose de similaire à Page2, tandis que l'utilisateur voit toujours la page1 affichée. Une fois la publication réussie, vous redirigez le navigateur vers la page 2.

Méthode 2: Publier + Rediriger vers soi

C'est une technique courante sur les forums. Form on Page1 publie les données sur Page2, Page2 traite les données et fait ce qui doit être fait, puis il effectue une redirection HTTP sur lui-même. De cette façon, la dernière «action» dont le navigateur se souvient est un simple GET sur la page 2, de sorte que le formulaire n'est pas soumis à nouveau sur F5.

CodeTwice
la source
2
Une variante de la méthode 2 est une redirection vers une autre page. Par exemple, vous POSTEZ sur example.com/save.html et une fois l'enregistrement terminé, vous redirigez vers example.com/list.html .
Guillaume
1
Avec la méthode 1, j'utiliserais le plugin jQuery nommé BlockUI pour informer le client que quelque chose se passe.
Shikiryu
J'utilise la méthode 2 mais elle me demande de soumettre à nouveau si je la rafraîchis. Quelqu'un ayant un problème similaire à celui-ci?
enthousiaste
Êtes-vous sûr que la redirection HTTP fonctionne correctement? Ouvrez l'inspecteur de réseau / firebug / tout ce que votre navigateur a pour inspecter les requêtes HTTP sortantes et vérifier les appels HTTP. Vous devriez voir le premier (publier les données du formulaire) se produire avec la méthode POST, renvoyer le code HTTP 301 avec l'en-tête Location pointant vers lui-même, puis immédiatement vous devriez voir une autre requête HTTP sur la même page avec la méthode GET.
CodeTwice
@CodeTwice: Dans mon cas, page1 publie sur page2, page2 traite les données et affiche une page (avec des valeurs passées au modèle). Où la redirection devrait-elle se produire? .. La page n'a pas de requêtes GET.
user1050619
24

Vous devez utiliser PRG - modèle Post / Redirect / Get et vous venez d'implémenter le P de PRG. Vous devez rediriger . (De nos jours, vous n'avez pas du tout besoin de redirection. Voyez ceci )

PRG est un modèle de conception de développement Web qui empêche certaines soumissions de formulaires en double, ce qui signifie, Soumettre le formulaire (Post Request 1) -> Redirect -> Get (Request 2)

Under the hood

Code d'état de redirection - HTTP 1.0 avec HTTP 302 ou HTTP 1.1 avec HTTP 303

Une réponse HTTP avec un code d'état de redirection fournira en outre une URL dans le champ d'en-tête de l'emplacement. L'agent utilisateur (par exemple un navigateur Web) est invité par une réponse avec ce code à faire une deuxième requête, sinon identique, à la nouvelle URL spécifiée dans le champ de localisation.

Le code d'état de la redirection vise à garantir que dans cette situation, le navigateur de l'utilisateur Web peut actualiser en toute sécurité la réponse du serveur sans provoquer la nouvelle soumission de la requête HTTP POST initiale.

Double Submit Problem

Problème de soumission double

Post/Redirect/Get Solution

Publier / rediriger / obtenir une solution

La source

Angelin Nadar
la source
2
Bonne explication. Je me demande ce qui se passera si l'utilisateur clique sur le bouton Précédent du navigateur après la redirection. La fenêtre contextuelle "Confirmer la nouvelle soumission du formulaire" s'affiche à nouveau. Je suppose que même si la fenêtre contextuelle de confirmation ne s'affiche pas à nouveau, une demande de publication sur la page 1 avec les mêmes données sera faite à nouveau et une fois de plus l'utilisateur sera redirigé vers la page 2. J'ai une série de formulaires, form1, form2, form3. comment peut revenir de la forme "n" à la forme "n-1" de manière transparente. Question aléatoire: Où avez-vous étudié le modèle de conception PRG
Rpant
@Rpant sur chrome, le fichier php qui envoie l'en-tête de l'emplacement n'apparaît même pas dans l'historique du navigateur, donc le bouton de retour vous ramène simplement au formulaire.
FluorescentGreen5
@Angelin Après la redirection, comment get obtiendra les données? Par exemple, lorsque je poste des données sur / some_url et que je redirige vers / some_url, ce qui fait une requête GET. Comment savoir quelle devrait être la réponse car / some_url est générique et ne contient pas un id comme / some_url / <id>?
Amit Tripathi
@AmitTripathi vous devez vous créer. Par exemple: la demande POST pourrait consister à insérer des données client alors que GET afficherait les données insérées avec succès. Vous pourrez afficher les données car il ne s'agissait que des données du formulaire ou réutiliser la vue de la page client en récupérant la base de données de ce client par l'identifiant client que vous avez reçu après l'insertion réussie dans la base de données.
Angelin Nadar le
Mais je suis d'accord avec la solution @Eugen Konkov
Angelin Nadar le
10

Directement, vous ne pouvez pas, et c'est une bonne chose. L'alerte du navigateur est là pour une raison. Ce fil devrait répondre à votre question:

Empêcher le bouton Retour d'afficher l'alerte de confirmation POST

Deux solutions de contournement clés suggérées étaient le modèle PRG et une soumission AJAX suivie d'une relocalisation de script.

Notez que si votre méthode autorise une méthode de soumission GET et non POST, cela résoudrait à la fois le problème et correspondrait mieux aux conventions. Ces solutions sont fournies dans l'hypothèse où vous voulez / avez besoin de POST des données.

Davin
la source
8

Le seul moyen d'être sûr à 100% que le même formulaire ne sera jamais soumis deux fois est d'intégrer un identifiant unique dans chacun de ceux que vous émettez et de suivre ceux qui ont été soumis sur le serveur. Le piège est que si l'utilisateur sauvegarde sur la page où se trouvait le formulaire et entre de nouvelles données, le même formulaire ne fonctionnera pas.

Blrfl
la source
6

Il y a deux parties à la réponse:

  1. Assurez-vous que les publications en double ne gâchent pas vos données côté serveur. Pour ce faire, intégrez un identifiant unique dans la publication afin de pouvoir rejeter les demandes ultérieures côté serveur. Ce modèle est appelé récepteur idempotent en termes de messagerie.

  2. Assurez-vous que l'utilisateur n'est pas gêné par la possibilité de soumissions en double par les deux

    • redirection vers un GET après le POST (modèle POST redirect GET)
    • désactivation du bouton en utilisant javascript

Rien de ce que vous faites sous 2. n'empêchera totalement les soumissions en double. Les gens peuvent cliquer très rapidement et les pirates peuvent quand même publier. Vous avez toujours besoin 1. si vous voulez être absolument sûr qu'il n'y a pas de doublons.

iwein
la source
2

Si vous actualisez une page avec des données POST, le navigateur confirmera votre nouvelle soumission. Si vous utilisez des données GET, le message ne sera pas affiché. Vous pouvez également avoir la deuxième page, après avoir enregistré la soumission, redirigée vers une troisième page sans données.

Joël
la source
2

Eh bien, j'ai trouvé que personne n'avait mentionné cette astuce.

Sans redirection, vous pouvez toujours empêcher la confirmation du formulaire lors de l'actualisation.

Par défaut, le code du formulaire est comme ceci:

<form method="post" action="test.php">

maintenant, changez-le en <form method="post" action="test.php?nonsense=1">

Vous verrez la magie.

Je suppose que c'est parce que les navigateurs ne déclenchent pas le popup d'alerte de confirmation s'il obtient une méthode GET (chaîne de requête) dans l'url.

Surligner
la source
2

Vous pouvez le faire en utilisant jquery

<script>
   $(document).ready(function(){
   window.history.replaceState('','',window.location.href)
   });
</script>

C'est le moyen le plus élégant d'empêcher à nouveau les données après leur soumission en raison de leur publication.

J'espère que cela t'aides.

noobprogrammer
la source
0

Le modèle PRG peut uniquement empêcher la nouvelle soumission provoquée par l'actualisation de la page. Ce n'est pas une mesure sûre à 100%.

Habituellement, je prendrai les mesures ci-dessous pour empêcher une nouvelle soumission:

  1. Côté client - Utilisez javascript pour éviter les clics en double sur un bouton qui déclenchera l'envoi du formulaire. Vous pouvez simplement désactiver le bouton après le premier clic.

  2. Côté serveur - Je vais calculer un hachage sur les paramètres soumis et enregistrer ce hachage dans la session ou la base de données, de sorte que lorsque la soumission dupliquée a été reçue, nous pouvons détecter la duplication, puis une réponse appropriée au client. Cependant, vous pouvez réussir à générer un hachage côté client.

Dans la plupart des cas, ces mesures peuvent aider à empêcher une nouvelle soumission.

ehe888
la source
0

J'aime vraiment la réponse de @ Angelin. Mais si vous avez affaire à du code hérité où ce n'est pas pratique, cette technique peut fonctionner pour vous.

En haut du fichier

// Protect against resubmits
if (empty($_POST))  {
   $_POST['last_pos_sub'] = time();
} else {
     if (isset($_POST['last_pos_sub'])){
        if ($_POST['last_pos_sub'] == $_SESSION['curr_pos_sub']) {
           redirect back to the file so POST data is not preserved
        }
        $_SESSION['curr_pos_sub'] = $_POST['last_pos_sub'];
     }
}

Puis à la fin du formulaire, inscrivez-vous last_pos_subcomme suit:

<input type="hidden" name="last_pos_sub" value=<?php echo $_POST['last_pos_sub']; ?>>
Scott C Wilson
la source
0

Essayez tris:

function prevent_multi_submit($excl = "validator") {
    $string = "";
    foreach ($_POST as $key => $val) {
    // this test is to exclude a single variable, f.e. a captcha value
    if ($key != $excl) {
        $string .= $key . $val;
    }
    }
    if (isset($_SESSION['last'])) {
    if ($_SESSION['last'] === md5($string)) {
        return false;
    } else {
        $_SESSION['last'] = md5($string);
        return true;
    }
    } else {
    $_SESSION['last'] = md5($string);
    return true;
    }
}

Comment utiliser / exemple:

if (isset($_POST)) {
    if ($_POST['field'] != "") { // place here the form validation and other controls
    if (prevent_multi_submit()) { // use the function before you call the database or etc
        mysql_query("INSERT INTO table..."); // or send a mail like...
        mail($mailto, $sub, $body); // etc
    } else {
        echo "The form is already processed";
    }
    } else {
    // your error about invalid fields
    }
}

Police: https://www.tutdepot.com/prevent-multiple-form-submission/

Rômulo ZC Cunha
la source
0

utilisez js pour empêcher l'ajout de données:

if ( window.history.replaceState ) {
    window.history.replaceState( null, null, window.location.href );
}
Tran Anh Hien
la source