NSI · Première
Interactions Web : événements, formulaires et serveur
Quand tu soumets un formulaire, plusieurs étapes s'enchaînent : un événement déclenche un gestionnaire, le client prépare les données, le serveur les vérifie puis répond, et le navigateur affiche le résultat. HTML donne leur sens aux composants, CSS les présente et JavaScript programme les réactions.
Explications et exemples en accès libre. Ateliers, quiz et cartes avec l’abonnement.
Prévoir mon tempsExplications et exemples en accès libre
Une première étude des explications, schémas, exemples résolus et erreurs expliquées. Les activités, productions, quiz et cartes réservés à l’abonnement ne sont pas comptés ici.
- Comprendre1451 mots d’explication et 4 schémas
- 10 à 18 min
- Étudier les exemples et les erreurs18 cas, exemples et activités guidés
- 36 à 66 min
Étude du cours en accès libre, environ45 min à 1 h 25
Voir le calcul et le temps par étape
Le calcul suit automatiquement les explications et les tâches présentes dans le cours. Ses coefficients sont des repères de planification, pas des temps mesurés auprès d’élèves.
- Lecture active : 1451 mots, à raison de 160 à 220 mots par minute.
- Schémas : 4, avec 1 à 2 min pour lire chacun.
- Exemple guidé : 6 × 2 à 4 min.
- Suivre le code résolu et ses tests : 6 × 3 à 5 min.
- Comprendre une erreur expliquée : 6 × 1 à 2 min.
- HTML, CSS, JavaScript : quelle couche porte quel sens ?8 à 15 min
- Événement et gestionnaire : quelle transformation doit rester testable ?7 à 15 min
- Mettre à jour le DOM : texte ou balisage ?6 à 13 min
- Client et serveur : dans quel ordre le calcul se déroule-t-il ?8 à 15 min
- GET, POST et HTTPS : où voyagent les paramètres et que protège le chiffrement ?7 à 15 min
- Formulaire : comment valider sans exclure ni faire confiance au seul navigateur ?6 à 13 min
Les sous-totaux sont arrondis à la minute, puis additionnés. La fourchette totale est élargie aux cinq minutes voisines. Les étapes ci-dessus comprennent leurs explications et exemples ; elles ne s’ajoutent pas une seconde fois au total.
Adapte ce repère à tes acquis et au soin apporté aux exercices. Les pauses, les reprises, la consultation des sources externes et les révisions suivantes s’ajoutent selon tes besoins.
Avec les ateliers, le projet, le quiz et les cartes : environ 2 h 40 à 4 h 40, à répartir sur plusieurs séances.
Objectifs du cours
Ce que tu vas savoir faire
- Distinguer structure HTML, présentation CSS, comportement JavaScript, état d'interface et données transmises.
- Identifier composant, événement, cible, gestionnaire et mise à jour dans une trace d'interaction.
- Associer un gestionnaire avec addEventListener et conserver l'accessibilité clavier des contrôles natifs.
- Distinguer ce qui s'exécute sur le client et sur le serveur, puis ordonner requête, validation, calcul et réponse.
- Construire et lire des paramètres GET ou un corps POST sans confondre méthode, confidentialité et chiffrement.
- Analyser un formulaire, valider aux deux niveaux et insérer une saisie comme texte plutôt que comme HTML.
Étape du cours · 8 à 15 min
1. HTML, CSS, JavaScript : quelle couche porte quel sens ?
HTML organise le document : un titre, une étiquette, un champ, un bouton et une zone de résultat ont chacun un rôle. CSS règle leur présentation, par exemple l'espacement ou le contraste. JavaScript associe une réaction à un événement. Une couleur et un gestionnaire de clic ne donnent donc pas, à eux seuls, les propriétés d'un bouton à un div. Utilise un vrai button, dont l'activation au clavier existe déjà.
Dans un formulaire, distingue trois attributs. id identifie un élément dans le document ; for relie une étiquette à l'élément portant cet identifiant ; name donne le nom sous lequel la valeur du champ sera transmise. Ainsi, id="quantite" et name="valeur" peuvent désigner le même champ : l'étiquette vise quantite, mais la donnée envoyée s'appelle valeur.
Le formulaire indique sa destination avec action et sa méthode avec method. Un bouton type="submit" demande sa soumission ; un bouton type="button" déclenche une action locale sans soumettre le formulaire par défaut. Le petit modèle de composants ci-dessous vérifie les identifiants et les étiquettes. Il donne un id à chaque composant suivi ; tous les éléments HTML n'ont pas besoin d'en posséder. Le projet final réunit ces composants dans un document HTML complet à ouvrir dans ton navigateur.
Voir pour comprendre
Trois couches, trois responsabilités
Un même bouton de calcul traverse les trois couches.
| Couche | Exemple | Rôle |
|---|---|---|
| HTML | button type="submit" | Nommer une action et fournir son activation native |
| CSS | :focus-visible, espacement | Rendre le contrôle et son focus perceptibles |
| JavaScript | addEventListener('submit', ...) | Lire la saisie, appeler le traitement et afficher sa réponse |
Lis le schéma. Si le résultat passe de 4 à 16 sans changer de couleur, quelle couche programme ce changement ?
La structure, la présentation et le comportement se complètent. CSS ne transforme pas un div en bouton.
Exemples résolus et erreurs expliquées
Lire un champ sans confondre ses noms
- Le formulaire contient
<label for="quantite">Entier</label>,<input id="quantite" name="valeur" value="4">et un bouton de soumission. Trouver l'étiquette : L'attribut for vaut quantite. Il vise l'input dont l'id est quantite, même si son name est différent. - Identifier la donnée : La paire transmise pour cet input actif est valeur=4. Le nom vient de name, pas du texte de l'étiquette ni de id.
- Lire le formulaire : Avec action="/calcul" et method="post", la destination est /calcul et les données sont dans le corps de la soumission HTML ordinaire.
- Tester une modification : Si tu retires name, ce champ texte n'est plus inclus dans les données du formulaire. Si tu changes seulement id, il faut aussi adapter for ; name reste valeur.
Conclusion. Lis séparément l'identification dans le document, le nom de la donnée et les modalités d'envoi.
Laboratoire de code
Languejavascript
Butvalider un modèle simplifié de composants avant de construire le document
Code solution
function assert(condition, message = 'assertion') { if (!condition) throw new Error(message); }
function verifierInterface(composants) {
const erreurs = [];
const ids = new Set();
for (const composant of composants) {
if (!composant.id) erreurs.push('identifiant absent');
else if (ids.has(composant.id)) erreurs.push(`identifiant dupliqué:${composant.id}`);
else ids.add(composant.id);
if (composant.role === 'champ' && composant.labelFor !== composant.id) erreurs.push(`étiquette absente:${composant.id}`);
if (composant.role === 'action' && composant.element !== 'button') erreurs.push(`action non native:${composant.id}`);
}
return erreurs;
}Tests
const correcte = [{id:'nom', role:'champ', labelFor:'nom', element:'input'}, {id:'calculer', role:'action', element:'button'}];
assert(verifierInterface(correcte).length === 0);
assert(verifierInterface([{id:'x',role:'champ',labelFor:'autre',element:'input'}])[0] === 'étiquette absente:x');
assert(verifierInterface([{id:'go',role:'action',element:'div'}])[0] === 'action non native:go');
assert(verifierInterface([{id:'x',role:'texte',element:'p'},{id:'x',role:'texte',element:'p'}]).includes('identifiant dupliqué:x'));Trace
- le champ nom enregistre id=nom puis vérifie labelFor=nom : aucune erreur
- le bouton calculer possède un nouvel id et l'élément natif button : aucune erreur
- un div déclaré action est signalé, car ajouter un clic ne lui donne ni clavier ni sémantique de bouton
Clinique de bogue
Indice observél'action n'a pas de rôle de bouton au clavier et la valeur titre est injectée comme HTML
CauseLe composant emploie un div avec gestionnaire en ligne et concatène une valeur dans le balisage. Il perd la sémantique native, sépare mal structure et comportement et ouvre une injection.
Étape du cours · 7 à 15 min
2. Événement et gestionnaire : quelle transformation doit rester testable ?
Un événement signale une occurrence, par exemple un clic, une saisie avec input ou une soumission avec submit. addEventListener associe une fonction à un type d'événement : on écrit addEventListener('click', agir), sans appeler agir() pendant l'inscription. Le gestionnaire reçoit ensuite l'objet événement lorsqu'il est invoqué.
Dans un bouton contenant un span, un clic sur le texte peut avoir le span pour target. Pendant l'exécution de l'écouteur installé sur le bouton, currentTarget est le bouton. Lire evenement.currentTarget.dataset permet donc de retrouver son action même si l'élément visé est un enfant. Le gestionnaire lit l'action, appelle une fonction de calcul puis met à jour l'affichage.
Le compteur ci-dessous retourne un nouvel objet et conserve les autres propriétés de l'état. Son domaine est constitué d'entiers exactement représentables ; le pas est un entier positif. Les actions sont incrémenter, décrémenter et réinitialiser. Une action inconnue rend une copie inchangée. Un bouton natif déclenche déjà son clic au clavier : un second gestionnaire qui incrémente sur keydown pourrait compter deux fois une seule activation.
Voir pour comprendre
Un clic, une transition, un rendu
Le compteur vaut 4 et le bouton demande +1.
- 1ÉvénementLe bouton natif est activé ; le gestionnaire lit l'action.
- 2TransitionLa fonction reçoit l'état 4 et renvoie un nouvel état 5.
- 3RenduLe gestionnaire présente 5 avec textContent. L'ancien état reste à 4.
Lis le schéma. Explique quel maillon change si l'activation vient du clavier. Le calcul doit-il être exécuté deux fois ?
Le bouton sait déjà s'activer au clavier. Un second gestionnaire qui incrémente aussi peut doubler une seule action.
Exemples résolus et erreurs expliquées
Du span cliqué au nouvel état
- Le compteur vaut 4. Le bouton porte data-action="incrementer" et data-pas="2" ; tu cliques sur le span qu'il contient. Repérer l'événement : Le clic part du span. L'écouteur installé sur le bouton reçoit cet événement pendant sa propagation.
- Lire la bonne cible : Dans cet écouteur, target désigne le span et currentTarget le bouton. Le dataset utile appartient au bouton.
- Calculer : actionDepuisBouton convertit la chaîne '2' en entier 2. transition retourne un nouvel état dont le compteur vaut 6 ; l'ancien reste à 4.
- Rendre une seule fois : Le gestionnaire affecte le nouvel état puis écrit 6 dans output. L'activation clavier suit le même calcul, sans ajouter un second incrément.
Conclusion. Sépare ce qui déclenche l'action, ce qui calcule la valeur et ce qui la présente.
Laboratoire de code
Languejavascript
Butséparer la transition d'état du gestionnaire DOM et tester toutes les actions
Code solution
function assert(condition, message = 'assertion') { if (!condition) throw new Error(message); }
function transition(etat, action) {
if (!Number.isSafeInteger(etat.compteur)) throw new Error('compteur entier sûr attendu');
if (action.type === 'reinitialiser') return {...etat, compteur: 0};
if (!['incrementer', 'decrementer'].includes(action.type)) return {...etat};
if (!Number.isSafeInteger(action.pas) || action.pas <= 0) throw new Error('pas entier positif attendu');
const compteur = etat.compteur + (action.type === 'incrementer' ? action.pas : -action.pas);
if (!Number.isSafeInteger(compteur)) throw new Error('compteur hors domaine');
return {...etat, compteur};
}
function actionDepuisBouton(dataset) {
const brut = dataset.pas ?? '1';
if (typeof brut !== 'string' || !/^[0-9]+$/.test(brut)) throw new Error('pas mal écrit');
const pas = Number(brut);
if (!Number.isSafeInteger(pas) || pas <= 0) throw new Error('pas entier positif attendu');
return {type: dataset.action, pas};
}Tests
const initial = {compteur: 4, unite: 'clics'};
const suivant = transition(initial, {type:'incrementer', pas:2});
assert(suivant.compteur === 6 && suivant.unite === 'clics');
assert(initial.compteur === 4 && suivant !== initial);
assert(transition(initial,{type:'decrementer',pas:3}).compteur === 1);
assert(transition(initial,{type:'reinitialiser'}).compteur === 0);
assert(actionDepuisBouton({action:'incrementer',pas:'5'}).pas === 5);
assert(actionDepuisBouton({action:'incrementer'}).pas === 1);
assert(transition(initial,{type:'inconnue'}).compteur === 4);
for (const pas of ['', '0', '-1', '1.5', '1e1', true]) {
let refuse = false; try { actionDepuisBouton({action:'incrementer',pas}); } catch { refuse = true; }
assert(refuse);
}Trace
- Un clic sur le span du bouton a le span pour target ; l'écouteur du bouton lit currentTarget.dataset.
- L'action {type:'incrementer', pas:1} et l'état {compteur:4} produisent un nouvel objet {compteur:5}.
- Le gestionnaire conserve le nouvel état puis écrit 5 dans output avec textContent.
Clinique de bogue
Indice observél'état initial est modifié et une comparaison avant-après ou un historique devient impossible
CauseLa fonction modifie l'objet reçu, renvoie la même référence et ignore le pas demandé. Une valeur affichée peut donc sembler plausible alors que l'ancien état a disparu. La correction conserve les propriétés de l'état et respecte les trois actions du laboratoire.
Étape du cours · 6 à 13 min
3. Mettre à jour le DOM : texte ou balisage ?
Le DOM représente le document comme un arbre d'objets. document.querySelector('#resultat') cherche l'élément portant cet identifiant ; champ.value lit une saisie ; sortie.textContent = texte remplace le contenu de la sortie par du texte. Pour que la recherche trouve sa cible, le script doit s'exécuter après la création de l'élément, par exemple en fin de body ou dans un fichier chargé avec defer.
Une chaîne comme <strong>4</strong> peut être une donnée à montrer, pas une consigne de mise en forme. Affectée à textContent, elle reste du texte visible, chevrons compris. Affectée à innerHTML, elle est analysée comme du balisage et crée un élément strong. Ne donne pas ce pouvoir à une saisie : construis la structure avec des éléments maîtrisés, puis affecte les valeurs textuelles.
Le laboratoire utilise un objet de test pour vérifier quelle propriété reçoit la valeur. Dans un vrai élément DOM, les propriétés ne sont pas indépendantes : après une affectation à textContent, lire innerHTML donne la sérialisation du nouveau contenu, avec les chevrons échappés. Le bon test navigateur vérifie donc le texte et l'absence d'élément créé, pas une ancienne valeur d'innerHTML inchangée.
Exemples résolus et erreurs expliquées
Afficher du texte qui ressemble à une balise
- On veut montrer exactement
<strong>4</strong>dans un élément p vide. Distinguer donnée et structure : Le résultat attendu contient les chevrons. Il ne s'agit pas de mettre 4 en gras. - Choisir l'affectation : Avec p.textContent = '<strong>4</strong>', le navigateur crée un contenu textuel, pas un enfant strong.
- Vérifier le DOM : p.textContent contient la chaîne entière et p.querySelector('strong') vaut null. p.innerHTML contient les chevrons encodés avec < et >.
- Comparer les deux opérations : Sur un autre p et avec cette seule constante maîtrisée, innerHTML = '<strong>4</strong>' crée un enfant strong. C'est cette interprétation que l'on évite pour les saisies.
Conclusion. Teste le contenu et la structure du vrai document : une simulation d'objet ne remplace pas un moteur HTML.
Laboratoire de code
Languejavascript
Butrendre une valeur comme texte et tester qu'aucune interprétation HTML n'est demandée
Code solution
function assert(condition, message = 'assertion') { if (!condition) throw new Error(message); }
function afficherTexte(noeud, valeur) {
noeud.textContent = String(valeur);
return noeud;
}
function rendreResultat(noeud, modele) {
const texte = modele.ok ? `Résultat : ${modele.valeur}` : `Erreur : ${modele.message}`;
return afficherTexte(noeud, texte);
}Tests
const noeud = {textContent:''};
afficherTexte(noeud,'<strong>4</strong>');
assert(noeud.textContent === '<strong>4</strong>');
assert(!Object.prototype.hasOwnProperty.call(noeud, 'innerHTML'));
assert(rendreResultat({textContent:''},{ok:true,valeur:42}).textContent === 'Résultat : 42');
assert(rendreResultat({textContent:''},{ok:false,message:'entier attendu'}).textContent === 'Erreur : entier attendu');Trace
- La chaîne '<strong>4</strong>' ressemble à du HTML, mais le contrat demande d'afficher ses caractères.
- afficherTexte écrit dans textContent. L'objet de test confirme cette affectation sans simuler un parseur HTML.
- Dans le navigateur, la sortie possède un nœud texte et aucun enfant strong ; lire innerHTML montre les chevrons échappés.
Clinique de bogue
Indice observéune saisie contenant du balisage est interprétée par le navigateur au lieu d'être affichée littéralement
CauseLa concaténation mélange contenu non fiable et syntaxe HTML, puis innerHTML déclenche l'analyse du tout. Le résultat visuel attendu ne justifie pas de donner à la saisie un pouvoir structurel.
Étape du cours · 8 à 15 min
4. Client et serveur : dans quel ordre le calcul se déroule-t-il ?
Le navigateur joue le rôle de client : il peut demander un document, soumettre des données puis afficher ce qu'il reçoit. Le serveur reçoit la requête, détermine le traitement demandé, vérifie les données et les droits nécessaires, puis construit la réponse. Une page et ses images, feuilles CSS ou scripts peuvent demander plusieurs requêtes. Après une réponse, c'est le navigateur qui construit ou modifie le DOM affiché.
Dans notre calcul fictif, le client prépare un objet de méthode POST, de chemin /calcul et de corps contenant une chaîne. Le serveur simulé vérifie le chemin, la méthode puis la valeur : des chiffres décimaux, éventuellement entourés d'espaces, représentant un entier de 0 à 10. '04' est accepté comme 4 ; '4.0', '1e1', '0xA', une chaîne vide ou un nombre déjà converti sont refusés par ce contrat.
Le modèle retourne 200 pour un calcul réussi, 400 pour une valeur invalide, 404 pour un autre chemin et 405 pour une méthode non acceptée. Il manipule des objets déjà décodés : il ne réalise ni transport HTTP, ni décodage JSON, ni authentification. Dans le projet, tu peux fabriquer une requête qui évite le contrôle du formulaire ; le serveur simulé doit encore la refuser. Sur un vrai service, ce second contrôle s'exécute côté serveur.
Voir pour comprendre
Qui contrôle quoi ?
Dans ce modèle local, le navigateur envoie la chaîne « 4 » et le serveur simulé calcule son carré.
| Lieu | Action | Ce qui ne suffit pas |
|---|---|---|
| Client avant envoi | aider à saisir et construire la requête | un champ min/max ne protège pas le serveur |
| Serveur à réception | vérifier présence, type et domaine, puis calculer 16 | une requête peut être fabriquée sans le formulaire |
| Client au retour | lire le statut puis afficher résultat ou erreur | le statut et le corps doivent guider le résultat affiché |
Lis le schéma. Suis une requête portant une chaîne vide : à quel maillon doit-elle être refusée même si le bouton était désactivé ?
La validation du formulaire peut être évitée. Le serveur applique donc ses propres contrôles, même pour une requête fabriquée directement.
Exemples résolus et erreurs expliquées
Suivre '4', puis une requête contenant '11'
- Le champ contient la chaîne '4'. Le client prépare {methode:'POST', chemin:'/calcul', corps:{valeur:'4'}} ; ce sont les données de notre modèle, pas les octets d'un message HTTP.
- Le serveur simulé reconnaît /calcul et POST. Il vérifie la syntaxe de '4', convertit en entier, vérifie la plage puis calcule 4 × 4 = 16.
- Il retourne {statut:200, corps:{carre:16}}. Le client choisit le texte 'Carré : 16' et le présente avec textContent.
- Une requête fabriquée directement avec corps.valeur='11' arrive sans passer par le formulaire. Le serveur renvoie 400 et ne calcule aucun résultat présenté comme valide.
Requête HTTP/1.1 illustrative : envoi d'un formulaire
POST /calcul HTTP/1.1
Host: exemple.test
Content-Type: application/x-www-form-urlencoded
Content-Length: 8
valeur=4Réponse HTTP/1.1 illustrative : résultat en JSON
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 12
{"carre":16}Conclusion. Le client aide à saisir ; le serveur décide si les données reçues respectent son contrat. Dans les deux messages HTTP/1.1 illustratifs, une ligne vide sépare les en-têtes du corps ; Content-Length compte les octets de ce corps. Le serveur doit décoder valeur=4 avant d'appliquer la règle modélisée. En HTTP/2 et HTTP/3, l'encodage des messages diffère.
Laboratoire de code
Languejavascript
Butsimuler la chaîne client-requête-serveur-réponse-client avec validation répétée
Code solution
function assert(condition, message = 'assertion') { if (!condition) throw new Error(message); }
function creerRequete(valeur) {
if (typeof valeur !== 'string') throw new Error('chaîne du champ attendue');
return {methode:'POST', chemin:'/calcul', corps:{valeur}};
}
function traiterServeur(requete) {
if (!requete || typeof requete !== 'object') return {statut:400, corps:{erreur:'requête attendue'}};
if (requete.chemin !== '/calcul') return {statut:404, corps:{erreur:'chemin inconnu'}};
if (requete.methode !== 'POST') return {statut:405, entetes:{Allow:'POST'}, corps:{erreur:'méthode non acceptée'}};
const brut = requete.corps?.valeur;
if (typeof brut !== 'string' || !/^[0-9]+$/.test(brut.trim())) return {statut:400, corps:{erreur:'entier 0..10 attendu'}};
const nombre = Number(brut.trim());
if (!Number.isInteger(nombre) || nombre < 0 || nombre > 10) return {statut:400, corps:{erreur:'entier 0..10 attendu'}};
return {statut:200, corps:{carre:nombre * nombre}};
}
function modeleClient(reponse) {
if (reponse.statut === 200) return {ok:true, texte:`Carré : ${reponse.corps.carre}`};
return {ok:false, texte:`Erreur : ${reponse.corps.erreur}`};
}Tests
const requete = creerRequete('4');
assert(requete.methode === 'POST' && requete.corps.valeur === '4');
assert(traiterServeur(requete).corps.carre === 16);
assert(modeleClient(traiterServeur(requete)).texte === 'Carré : 16');
assert(traiterServeur(creerRequete('0')).corps.carre === 0);
assert(traiterServeur(creerRequete(' 04 ')).corps.carre === 16);
for (const valeur of ['', ' ', '-1', '11', 'abc', '4.0', '1e1', '0xA', null, true, 4, [], {}]) {
assert(traiterServeur({methode:'POST',chemin:'/calcul',corps:{valeur}}).statut === 400);
}
assert(traiterServeur(null).statut === 400);
assert(traiterServeur({...requete,chemin:'/autre'}).statut === 404);
assert(traiterServeur({...requete,methode:'GET'}).statut === 405);
assert(traiterServeur({...requete,methode:'GET'}).entetes.Allow === 'POST');Trace
- Client : la chaîne '4' lue dans le champ devient corps.valeur, sans conversion anticipée ni requête réseau.
- Serveur simulé : /calcul et POST sont acceptés ; '4' respecte la syntaxe puis la plage 0..10. Le carré vaut 16.
- Client : le statut 200 conduit au texte 'Carré : 16'. Une entrée '' donne 400 et un message d'erreur, pas un carré égal à 0.
Clinique de bogue
Indice observéune chaîne vide devient 0, une valeur hors domaine est acceptée et une chaîne alphabétique produit NaN avec statut 200
CauseLe serveur calcule avant de définir et vérifier le domaine. La conversion implicite de JavaScript masque certaines erreurs ; le statut de succès affirme alors un résultat qui n'a pas été validé.
Étape du cours · 7 à 15 min
5. GET, POST et HTTPS : où voyagent les paramètres et que protège le chiffrement ?
Une requête HTTP indique une méthode, une cible, des en-têtes et éventuellement un corps. GET demande une représentation d'une ressource. Sa sémantique ne demande pas de modification métier : rechercher un cours ne doit pas, par exemple, supprimer un compte. Cela n'interdit pas au serveur d'écrire un journal, et deux GET successifs peuvent recevoir des contenus différents si la ressource a évolué.
Pour un formulaire HTML envoyé en GET, les couples nom-valeur se trouvent dans la partie de requête de l'URL, après ? et avant un éventuel #. Le fragment n'est pas transmis au serveur par HTTP. Avec POST, les données du formulaire sont placées dans le corps. Par défaut, un formulaire HTML ordinaire les encode en application/x-www-form-urlencoded ; du JSON exige une préparation adaptée. Une URL de POST peut elle aussi contenir des paramètres.
HTTPS protège la confidentialité et l'intégrité du transport et authentifie le serveur auprès du client selon les certificats vérifiés. POST ne fournit pas ce chiffrement. Les extrémités reçoivent toujours les données : évite les informations sensibles dans l'URL, les traces ou les captures. Le laboratoire ne fait aucun envoi ; analyser le schéma d'une URL n'est pas vérifier un certificat ni réaliser une connexion.
Voir pour comprendre
Méthode HTTP et protection du transit
GET, POST et HTTPS répondent à des questions différentes.
| Repère | Fonction | Limite |
|---|---|---|
| GET | obtenir une représentation ; paramètres dans l'URL | URL partageable, mémorisable et journalisable |
| POST | soumettre un corps, notamment pour une opération avec effet | la méthode ne chiffre rien |
| HTTPS | protéger le transit par TLS | les extrémités reçoivent encore les données |
Lis le schéma. Identifie ce qui relève de l'effet demandé, de la position des paramètres puis du transport.
Un corps POST n'est pas une promesse de confidentialité. La donnée doit aussi être minimisée et traitée correctement aux extrémités.
Exemples résolus et erreurs expliquées
Lire l'URL et le corps sans les mélanger
- Une recherche vise https://exemple.test/recherche?q=arbre&page=2#resultats : le chemin est /recherche, la partie de requête est q=arbre&page=2, le fragment est resultats.
- Le navigateur n'envoie pas #resultats dans la requête HTTP. Les valeurs q=arbre et page=2 font partie de la cible demandée.
- Pour un formulaire HTML ordinaire en POST contenant name='valeur' et la saisie '4', le corps encodé par défaut contient valeur=4. Notre fonction requetePost choisit au contraire le JSON et annonce application/json.
- Changer POST en GET ne change pas un transport HTTP en HTTPS. Changer http: en https: demande un transport protégé ; les données restent connues du navigateur et du serveur destinataire.
Conclusion. Pose trois questions : quelle opération est demandée, où sont les valeurs et comment le transport est-il protégé ?
Laboratoire de code
Languejavascript
Butpréparer des descriptions de requêtes, encoder les paramètres et distinguer une URL HTTPS d'une connexion vérifiée
Code solution
function assert(condition, message = 'assertion') { if (!condition) throw new Error(message); }
function requeteGet(chemin, parametres, champsSensibles = []) {
const url = new URL(chemin, 'https://exemple.test/');
if (!['http:', 'https:'].includes(url.protocol)) throw new Error('URL Web attendue');
for (const champ of champsSensibles) {
if (Object.prototype.hasOwnProperty.call(parametres, champ) || url.searchParams.has(champ)) {
throw new Error('champ sensible interdit dans URL');
}
}
for (const [nom, valeur] of Object.entries(parametres)) url.searchParams.set(nom, String(valeur));
url.hash = '';
return {methode:'GET', cible:url.href, corps:null};
}
function requetePost(chemin, donnees) {
const url = new URL(chemin, 'https://exemple.test/');
if (!['http:', 'https:'].includes(url.protocol)) throw new Error('URL Web attendue');
url.hash = '';
return {methode:'POST', cible:url.href, entetes:{'content-type':'application/json'}, corps:JSON.stringify(donnees)};
}
function utiliseHttps(cible, base = 'https://exemple.test/') {
try { return new URL(cible, base).protocol === 'https:'; }
catch { return false; }
}Tests
assert(requeteGet('/recherche',{q:'arbre',page:2}).cible === 'https://exemple.test/recherche?q=arbre&page=2');
assert(requeteGet('/liste?tri=nom#fin',{q:'a & b'}).cible === 'https://exemple.test/liste?tri=nom&q=a+%26+b');
assert(requeteGet('/liste?q=ancien',{q:'neuf'}).cible.endsWith('?q=neuf'));
assert(requetePost('/calcul?mode=carre',{valeur:'4'}).corps === '{"valeur":"4"}');
assert(requetePost('/calcul?mode=carre',{valeur:'4'}).cible.endsWith('/calcul?mode=carre'));
assert(utiliseHttps('/calcul') && utiliseHttps('HTTPS://EXEMPLE.TEST/'));
assert(!utiliseHttps('/calcul', 'http://exemple.test/'));
assert(!utiliseHttps('https://['));
let refuse=false; try { requeteGet('/x?secret=fictif',{},['secret']); } catch { refuse=true; } assert(refuse);Trace
- Le modèle résout /recherche contre une base HTTPS fictive et encode 'a & b' en a+%26+b ; & interne à la valeur ne devient pas un séparateur de champs.
- Les paramètres nommés remplacent ici ceux du même nom et les autres paramètres existants sont conservés. C'est le contrat de cette fonction, pas l'algorithme de soumission native d'un formulaire GET.
- POST encode ici un objet en JSON, distinct du format par défaut d'un formulaire HTML. utiliseHttps lit le schéma de l'URL résolue sans établir de connexion.
Clinique de bogue
Indice observéle secret est placé dans l'URL, susceptible d'apparaître dans historique, captures, copier-coller et journaux
CauseL'encodage d'URL conserve une syntaxe valide, sans rendre la donnée secrète. Une valeur sensible reste lisible dans la cible après décodage. Le modèle corrigé décrit un corps séparé et une destination HTTPS ; son indicateur de journalisation est une consigne à implémenter, pas une protection active.
Étape du cours · 6 à 13 min
6. Formulaire : comment valider sans exclure ni faire confiance au seul navigateur ?
Un formulaire HTML construit des couples nom-valeur à partir des contrôles concernés. Pour un input texte, un name absent ou vide empêche son inclusion ; un champ disabled n'est pas transmis non plus. Une case non cochée est omise. Un champ readonly peut, lui, être transmis. Ces différences expliquent pourquoi un champ présent à l'écran n'apparaît pas toujours dans les données reçues.
Le gestionnaire de submit permet de traiter aussi bien le bouton de soumission que l'envoi au clavier. preventDefault() annule l'action par défaut de cet événement : dans le projet, il permet de simuler le traitement sans navigation ni envoi. Les messages sont écrits près du champ, reliés par aria-describedby ; aria-invalid signale l'erreur sans dépendre uniquement d'une couleur.
La règle choisie est précise : recevoir une chaîne, retirer les espaces autour, exiger des chiffres de 0 à 9, convertir puis vérifier l'intervalle 0..10. La chaîne vide n'est pas zéro ; '4.0' n'est pas une écriture autorisée ici, même si Number la convertirait en 4. Le résultat de validation ne livre une valeur normalisée qu'en cas de succès. Une erreur conserve la saisie et efface le résultat précédent pour ne pas le faire passer pour la réponse au nouvel essai.
Exemples résolus et erreurs expliquées
Ne pas afficher l'ancien succès après une erreur
- Premier essai : le champ contient '4'. La validation accepte la chaîne, le serveur simulé renvoie 200 et la page affiche Carré : 16.
- Deuxième essai : tu effaces le champ puis soumets. Number('') vaudrait 0, mais la règle de présence est examinée avant la conversion.
- La validation produit erreurs.nombre et valeurs=null. Le gestionnaire conserve le champ vide, affiche l'erreur reliée au champ et supprime le résultat Carré : 16 de l'essai précédent.
- Troisième essai : tu saisis '0'. La présence est établie, le domaine est respecté, l'erreur disparaît et le résultat devient Carré : 0.
Conclusion. Présence, syntaxe, domaine et état de l'interface sont quatre vérifications distinctes.
Laboratoire de code
Languejavascript
Butvalider le champ nombre selon le même domaine que le serveur et retourner une erreur reliée à ce champ
Code solution
function assert(condition, message = 'assertion') { if (!condition) throw new Error(message); }
function validerFormulaire(entree) {
const erreurs = {};
const brut = entree?.nombre;
if (typeof brut !== 'string' || brut.trim() === '') {
erreurs.nombre = 'Saisis un entier de 0 à 10.';
} else if (!/^[0-9]+$/.test(brut.trim())) {
erreurs.nombre = 'écris un entier avec des chiffres de 0 à 9';
} else {
const nombre = Number(brut.trim());
if (!Number.isInteger(nombre) || nombre < 0 || nombre > 10) erreurs.nombre = 'entier entre 0 et 10';
}
return {valeurs: Object.keys(erreurs).length ? null : {nombre:Number(brut.trim())}, erreurs};
}
function estValide(resultat) { return Object.keys(resultat.erreurs).length === 0; }Tests
assert(estValide(validerFormulaire({nombre:'0'})));
assert(validerFormulaire({nombre:''}).valeurs === null);
assert(validerFormulaire({nombre:'11'}).erreurs.nombre === 'entier entre 0 et 10');
assert(validerFormulaire({nombre:' 04 '}).valeurs.nombre === 4);
assert(validerFormulaire({nombre:'10'}).valeurs.nombre === 10);
for (const nombre of [null, true, 4, [], {}, '4.0', '1e1', '0xA', '-1']) assert(!estValide(validerFormulaire({nombre})));
assert(!estValide(validerFormulaire(null)));Trace
- La chaîne brute reste disponible : '' est refusée alors que '0' peut être convertie en zéro valide.
- Après le contrôle du type et de la syntaxe, '11' échoue sur l'intervalle ; erreurs.nombre permet de nommer la correction à faire.
- Un succès rend valeurs.nombre, sinon valeurs vaut null. Le serveur répète ses contrôles sur la requête reçue, indépendamment de ce résultat client.
Clinique de bogue
Indice observéune chaîne vide est convertie en 0 et acceptée, tandis qu'aucun message ne permet de savoir quel champ corriger
CauseLa conversion est effectuée avant le contrôle de présence et son résultat booléen écrase la cause de l'échec. Le contrat doit conserver la chaîne brute et retourner une erreur localisée.
Poursuivre avec l’abonnement
Passer de la lecture à la pratique
Lis les six étapes, les quatre schémas et les exemples résolus pour suivre une interaction Web.
Entraîne-toi avec six ateliers, dix questions corrigées, douze cartes et un projet HTML complet à essayer dans ton navigateur.
10 questions · 12 cartes. Ta reprise et tes révisions sont enregistrées dans ce navigateur. Elles ne se synchronisent pas entre appareils.
Accéder à l'entraînement Déjà abonné ? Se connecterVérifier et prolonger
Sources du cours
Édition Maxdecours · Vérifié le .
Spécialité NSI, Première générale · programme du BO spécial du 22 janvier 2019
- Programme officiel NSI Premièreévénements, client-serveur, HTTP, formulaires, GET, POST et chiffrement · consulté le 2026-09-05
- Éduscol, programmes et ressources NSIétat en vigueur et ressources d'accompagnement · consulté le 2026-09-05
- Éduscol, ÉvénementsDOM, événements, cible et addEventListener · consulté le 2026-09-05
- Éduscol, Interaction client-serveurrequêtes HTTP, couches, ordre client-serveur et formulaires · consulté le 2026-09-05
- WHATWG, HTML Living Standardsémantique primaire des formulaires, boutons et événements d'activation · consulté le 2026-09-05
- IETF, HTTP Semantics RFC 9110méthodes, messages, statuts et sémantique de HTTP · consulté le 2026-09-05
- W3C WAI, Forms Tutorialétiquettes, instructions, validation et retour accessible · consulté le 2026-09-05
- OWASP, Cross Site Scripting Prevention Cheat Sheetséparation contexte de sortie, texte et balisage non fiable · consulté le 2026-09-05
- WHATWG, DOM Standardévénements, currentTarget, target et contenu textuel du DOM · consulté le 2026-09-05
© 2026 Maxdecours.com · Comprendre et progresser