web-dev-qa-db-fra.com

Comment conserver le contenu du formulaire modifié lorsque vous quittez et revenez à la page HTTPS? (fonctionne avec HTTP)

  1. Entrer/modifier quelque chose dans une zone de texte
  2. Avant de soumettre le formulaire, quittez la page (par exemple en cliquant sur le bouton de retour du navigateur)
  3. Revenez à la page d'édition (par exemple en cliquant sur le bouton Suivant)

Résultat attendu: le contenu saisi dans la zone de texte doit toujours y être

Résultat actuel:

  • avec HTTPS : toutes les modifications ont disparu (mauvais!)
  • avec HTTP : les changements sont toujours là (bon!)

Pourquoi cela se produit-il lors de l'utilisation de HTTPS? Comment puis-je éviter cela? Le navigateur ou le site Web est-il responsable?

18
unor

Vous pouvez envisager les solutions suivantes:

L'attribut autocomplete (HTML5)

Cela ne semble pas lié puisque autocomplete indique au navigateur de remplir les champs avec les valeurs basées sur une entrée utilisateur antérieure qui ont été "soumises" avec le formulaire . Mais dans mes tests, j'ai vu cela; après avoir rempli le formulaire sans le soumettre; quand j'ai appuyé sur le bouton avant (historique) et que je suis revenu en arrière; les champs du formulaire étaient remplis automatiquement si je définissais autocomplete="on" et tous étaient effacés lorsqu'ils étaient définis sur "off".

Alors; (si vous ciblez des utilisateurs HTML5), vous pouvez utiliser cet attribut pour "mettre en cache" vos données de formulaire. (Fonctionne sur tous les principaux navigateurs, sauf Opera).

<form action="/update" method="post" autocomplete="on">
    Email:    <input type="text" id="email" /><br />
    Username: <input type="text" id="uname" /><br />
    Password: <input type="password" id="pwd" autocomplete="off"/><br />
    <input type="submit" />
</form> 

Notez que vous pouvez désactiver la fonction de saisie semi-automatique pour un champ spécifique (mot de passe dans ce cas) lorsque les autres contrôles du formulaire sont activés.

Remarques MSDN:

  • Si l'attribut de saisie semi-automatique est manquant, le champ passera par défaut à un état "on" si l'élément n'a pas de formulaire parent, ou si le formulaire a une saisie semi-automatique définie sur "on".
  • Les informations fournies par la fonction de saisie semi-automatique ne sont pas exposées au modèle objet et ne sont pas visibles sur une page Web tant que l'utilisateur n'a pas sélectionné l'une des suggestions comme valeur pour le champ de texte.

Enregistrez les données du formulaire non soumis localement:

Vous pouvez stocker les données d'entrée localement, juste avant la redirection de page ou lors d'un événement focus-out de chaque contrôle de formulaire:

Cookies

Les bons vieux cookies peuvent être utiles dans ce cas, mais vous devriez considérer les inconvénients:

  1. Même si vous pouvez chiffrer les valeurs par programme; puisque nous travaillerons côté client, les cookies ne sont pas vraiment sécurisés pour cela. Les cookies marqués Http-Only Et Secure ne nous seront pas utiles ici, car ces options sont utilisées pour appliquer SSL lorsque le cookie est "envoyé" (sécurisé) et n'est pas accessible à partir de Javascript (http uniquement) .
  2. Les navigateurs ont une limite de taille de cookie. De [~ # ~] msdn [~ # ~] : "La plupart des navigateurs prennent en charge les cookies jusqu'à 4096 octets. En raison de cette petite taille limite, les cookies sont mieux utilisés pour stocker de petites quantités de données ". Donc, si vous ne surveillez pas cette taille (lorsque vous écrivez le cookie et/ou en limitant la valeur du contrôle via maxlength les attributs); Cela pourrait être un problème. (et rogner la valeur est la pire chose dans ce cas).
  3. Les navigateurs ont également une limite au nombre de cookies pouvant être définis par domaine. Alors; lors du stockage des données du formulaire dans les cookies; au lieu de définir des cookies pour chaque valeur de champ de formulaire; vous devez les fusionner en un ou quelques cookies; pour que votre site ne dépasse pas cette limite.

Pourtant, le bon côté est qu'ils sont pris en charge par tous les navigateurs et si vous ne prévoyez pas de "mettre en cache" des données sensibles et trop longues via les cookies, vous pouvez utiliser la solution suivante. Si ce n'est pas le cas; il vaut mieux aller avec la suggestion suivante: localStorage.

// Below is just a demonstration and is not tested thoroughly for 
// production-ready web applications by any means.  
// But it should give you an idea.

/** 
 * Caches the user-input data from the targeted form, stores it in the cookies 
 * and fetches back to the form when requested or needed. 
 */
var formCache = (function () {
    var _form = null, 
        _formData = [],
        _strFormElements = "input[type='text'],"
                + "input[type='checkbox']," 
                + "input[type='radio']," 
                // + "input[type='password'],"  // leave password field out 
                + "input[type='hidden'],"
                // + "input[type='image'],"
                + "input[type='file'],"
                // more input types...
                + "input[type='email'],"
                + "input[type='tel'],"
                + "input[type='url'],"
                + "select,"
                + "textarea";

    function _warn() {
        console.log('formCache is not initialized.');
    }

    return {

        /**
         * Initializes the formCache with a target form (id). 
         * You can pass any container id for the formId parameter, formCache will 
         * still look for form elements inside the given container. If no form id 
         * is passed, it will target the first <form> element in the DOM. 
         */
        init: function (formId) {
            var f = (typeof formId === 'undefined' || formId === null || $.trim(formId) === '') 
                    ? $('form').first() 
                    : $('#' + formId);
            _form = f.length > 0 ? f : null;
            console.log(_form);
            return formCache; // make it chainable
        },

        /** 
         * Stores the form data in the cookies.
         */
        save: function () {
            if (_form === null) return _warn();

            _form
                .find(_strFormElements)
                .each(function() {
                    var f = $(this).attr('id') + ':' + formCache.getFieldValue($(this));
                    _formData.Push(f);
                });
            docCookies.setItem('formData', _formData.join(), 31536e3); // 1 year expiration (persistent)
            console.log('Cached form data:', _formData);
            return formCache;
        },

        /** 
         * Fills out the form elements from the data previously stored in the cookies.
         */
        fetch: function () {
            if (_form === null) return _warn();

            if (!docCookies.hasItem('formData')) return;
            var fd = _formData.length < 1 ? docCookies.getItem('formData').split(',') : _formData;
            $.each(fd, function (i, item) {
                var s = item.split(':');
                var elem = $('#' + s[0]);
                formCache.setFieldValue(elem, s[1]);
            });
            return formCache;
        },

        /** 
         * Sets the value of the specified form field from previously stored data.
         */
        setFieldValue: function (elem, value) {
            if (_form === null) return _warn();

            if (elem.is('input:text') || elem.is('input:hidden') || elem.is('input:image') ||
                    elem.is('input:file') || elem.is('textarea')) {
                elem.val(value);
            } else if (elem.is('input:checkbox') || elem.is('input:radio')) {
                elem.prop('checked', value);
            } else if (elem.is('select')) {
                elem.prop('selectedIndex', value);
            }
            return formCache;
        },

        /**
         * Gets the previously stored value of the specified form field.
         */
        getFieldValue: function (elem) {
            if (_form === null) return _warn();

            if (elem.is('input:text') || elem.is('input:hidden') || elem.is('input:image') ||
                elem.is('input:file') || elem.is('textarea')) {
                    return elem.val();
                } else if (elem.is('input:checkbox') || elem.is('input:radio')) {
                    return elem.prop('checked');
                } else if (elem.is('select')) {
                    return elem.prop('selectedIndex');
                }
            else return null;
        },

        /**
         * Clears the cache and removes the previously stored form data from cookies.
         */
        clear: function () {
            _formData = [];
            docCookies.removeItem('formData');
            return formCache;
        },

        /**
         * Clears all the form fields. 
         * This is different from form.reset() which only re-sets the fields 
         * to their initial values.
         */
        clearForm: function () {
            _form
                .find(_strFormElements)
                .each(function() {
                    var elem = $(this);
                    if (elem.is('input:text') || elem.is('input:password') || elem.is('input:hidden') || 
                        elem.is('input:image') || elem.is('input:file') || elem.is('textarea')) {
                        elem.val('');
                    } else if (elem.is('input:checkbox') || elem.is('input:radio')) {
                        elem.prop('checked', false);
                    } else if (elem.is('select')) {
                        elem.prop('selectedIndex', -1);
                    }
                });
            return formCache;
        }
    };
})();

// Save form data right before we unload the form-page
$(window).on('beforeunload', function (event) {
    formCache.save();
    return false;
});

// Initialize and fetch form data (if exists) when we load the form-page back
$(document).on('ready', function (event) {
    formCache.init().fetch();
});

Voici une démonstration de travail sur jsFiddle.

Remarque: Le script "lecteur/écrivain de cookies" du développeur .mozilla.org doit être inclus avec le code ci-dessus. Vous pouvez également utiliser Yahoo YUI 2: Cookie Utility qui a une méthode utile setSub () pour définir des sous-cookies dans un seul cookie, pour la limite de navigateur que j'ai mentionnée précédemment.

localStorage

Vous pouvez également utiliser des techniques plus modernes comme localStorage (HTML5). C'est plus sûr et plus rapide. Tous les principaux navigateurs prennent en charge cette fonctionnalité, y compris IE 8+. (De plus, iOS et Android!)

if (typeof Storage !== 'undefined') { // We have local storage support
    localStorage.username = 'Onur'; // to save to local storage
    document.getElementById('uname').value = localStorage.username; // to fetch from local storage
}

Donc, tout comme dans l'exemple des cookies;

$(window).on('beforeunload', function (event) {
    saveFormToLocalStorage();
    return false;
});

$(document).on('ready', function (event) {
    fillFormFromLocalStorage()
});

SessionStorage

Cela fonctionne à peu près de la même manière. Du W3C: l'objet sessionStorage est égal à l'objet localStorage, sauf qu'il stocke les données pour une seule session.

Enregistrer les données du formulaire sur le serveur/la base de données via Silent AJAX Post (s):

Ce n'est pas un moyen très efficace mais vous voudrez peut-être l'utiliser là où d'autres ne sont pas réalisables. Vous pouvez créer le message sur l'événement beforeunload et demander un message à l'utilisateur.

$(window).on('beforeunload', function (event) {
    //check if at least one field is filled out.
    //make the AJAX post if filled out.
    return "You are leaving the page without submitting the form...";
});

Récupérer les données précédemment enregistrées du serveur lors du chargement de la page:

Juste pour te rappeler; si l'utilisateur remplit un formulaire de "mise à jour", par exemple; vous pouvez toujours récupérer les données précédemment enregistrées sur le serveur et remplir automatiquement le formulaire (champs non sensibles).

Conclusion

Si vous en avez vraiment besoin et en vaut la peine; vous devriez envisager une solution multi-navigateur qui implémente un mécanisme de secours; tel que:

  • SI vous avez un support pour les fonctionnalités HTML5; utilisez HTML5 autocomplete attribut . (Vous pouvez incorporer l'attribut dans le code HTML au préalable, ou le définir via Javascript/jQuery lorsque vous testez la prise en charge du navigateur.)
  • AUTRE SI vous avez la prise en charge de l'objet Storage; aller avec localStorage;
  • ELSE IF [cookies que votre session actuelle stocke] + [taille du cookie dont vos données de formulaire ont besoin] <4096 octets; puis utilisez cookies.
  • AUTRE SI vous avez une application Web côté serveur, faites taire AJAX demande de stocker les données sur le serveur .
  • Sinon, ne le faites pas.

Remarque: Pour la détection des fonctionnalités HTML5, jetez un œil à ce page ou cette page ou vous pouvez utiliser Modernizr .

Problème HTTPS :

La raison, toutes les modifications de formulaire ont disparu lors de l'utilisation de [~ # ~] https [~ # ~] c'est que; c'est un protocole sécurisé. Les formulaires sont principalement utilisés pour la saisie par l'utilisateur et peuvent (probablement) contenir des données sensibles. Ce comportement semble donc naturel et attendu. La ou les solutions que j'offre ci-dessus fonctionneront de la même manière que sur HTTP. Cela devrait donc couvrir toutes vos préoccupations.

Lectures complémentaires:

63
Onur Yıldırım