Skip to content

Devine mon nombre - Client, serveur et HTTP

Objectifs

  • Distinguer ce qui s'exécute côté client (navigateur) et côté serveur
  • Observer et analyser des requêtes HTTP avec les outils de développement
  • Comprendre ce qui est mémorisé côté client et ce qui l'est côté serveur
  • Comparer les méthodes GET et POST et savoir quand les utiliser
  • Comprendre pourquoi HTTPS est nécessaire pour protéger des données sensibles

Mise en place

Structure des fichiers

Crée le dossier suivant dans ton espace de travail :

devine/
├── serveur.py
└── static/
    └── index.html

serveur.py

from flask import Flask, request, jsonify, send_from_directory
import random

app = Flask(__name__)  # ne pas chercher à comprendre cette ligne pour l'instant

NOMBRE_SECRET = random.randint(1, 100)
tentatives = 0

@app.route("/")
def accueil():
    return send_from_directory("static", "index.html")

@app.route("/deviner")
def deviner():
    global tentatives
    proposition = request.args.get("proposition", "")

    if not proposition.isdigit():
        return jsonify({"resultat": "erreur", "message": "Entre un nombre entier."})

    proposition = int(proposition)
    tentatives += 1

    if proposition < NOMBRE_SECRET:
        message = "Trop petit !"
    elif proposition > NOMBRE_SECRET:
        message = "Trop grand !"
    else:
        message = f"Gagne en {tentatives} tentatives !"

    return jsonify({"resultat": message, "tentatives": tentatives})

@app.route("/inscription", methods=["POST"])
def inscription():
    pseudo = request.form.get("pseudo")
    mdp = request.form.get("mot_de_passe")
    return f"<p>Recu : pseudo={pseudo}, mot_de_passe={mdp}</p>"

app.run(debug=True)

static/index.html

<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <title>Devine mon nombre</title>
</head>
<body>
  <h1>Devine le nombre (entre 1 et 100)</h1>

  <input type="number" id="proposition" min="1" max="100" placeholder="Ton nombre">
  <button id="btn">Deviner</button>

  <p id="resultat"></p>
  <p id="historique"></p>

  <h2>Creer un compte (simulation)</h2>
  <form action="/inscription" method="POST">
    <input type="text" name="pseudo" placeholder="Pseudo">
    <input type="password" name="mot_de_passe" placeholder="Mot de passe">
    <button type="submit">S'inscrire</button>
  </form>

  <script>
    const historique = [];  // memorise cote client

    document.getElementById("btn").addEventListener("click", function () {
      const valeur = document.getElementById("proposition").value;

      fetch("/deviner?proposition=" + valeur)
        .then(function (reponse) { return reponse.json(); })
        .then(function (donnees) {
          document.getElementById("resultat").textContent = donnees.resultat;
          historique.push(valeur);
          document.getElementById("historique").textContent =
            "Tentatives : " + historique.join(", ");
        });
    });
  </script>
</body>
</html>

Lancer le serveur

Dans le terminal de VSCode, installe Flask :

uv add flask

Puis exécute serveur.py directement depuis VSCode (bouton ▶ en haut à droite).

Ouvre ensuite http://localhost:5000 dans ton navigateur, puis ouvre les outils de développement (F12) et place-toi sur l'onglet Réseau.


Partie 1 - Observer les échanges entre client et serveur

Joue quelques tours : entre des nombres et clique sur « Deviner ».

Q1

Dans l'onglet Réseau, clique sur une des requêtes qui apparait. Recopie l'URL complète de la requête.

Q2

Comment s'appelle la partie de l'URL qui commence par ? ? Quel est le nom du paramètre transmis ? Quelle est sa valeur ?

Q3

Quelle méthode HTTP est utilisée ? (cherche dans les en-têtes de la requête)

Q4

Clique sur l'onglet Aperçu ou Réponse de cette requête. Que contient la réponse du serveur ? Sous quel format ?


Partie 2 - Client ou serveur ?

Q5

Complète le tableau suivant :

Action Côté client ou côté serveur ?
Afficher le message « Trop petit ! » dans la page
Comparer la proposition au nombre secret
Compter le nombre de tentatives
Mettre à jour la liste des tentatives affichée

Q6

Ouvre le fichier index.html et repère le tableau historique dans le code JavaScript.

  • Est-ce que ce tableau est envoyé au serveur à chaque requête ?
  • Est-ce que le serveur connait la liste de tes tentatives ?
  • Où est-il mémorisé ?

Q7

Ouvre le fichier serveur.py et repère la variable tentatives.

  • À quel moment est-elle modifiée ?
  • Que se passe-t-il si tu fermes et relances le serveur en cours de partie ?
  • Que se passe-t-il si deux élèves jouent en même temps sur le même serveur ?

Partie 3 - Modifier le comportement côté client

Ouvre index.html dans un éditeur de texte.

Q8

Repère la ligne suivante :

document.getElementById("btn").addEventListener("click", function () {

Que se passe-t-il quand l'utilisateur clique sur le bouton ? Dans quel ordre les actions sont-elles exécutées ?

Q9

Ajoute la ligne suivante juste après l'accolade ouvrante de la fonction :

console.log("Clic detecte, valeur = " + valeur);

Recharge la page, joue un tour, puis ouvre l'onglet Console des outils de développement. Que vois-tu ? Sur quelle machine ce code s'est-il exécuté ?

Q10

Modifie la requête pour envoyer la valeur 999 quel que soit ce que l'utilisateur a tapé. Comment le serveur réagit-il ? Que cela montre-t-il sur la confiance qu'on peut accorder aux données reçues côté serveur ?


Partie 4 - GET ou POST ? Confidentialité et chiffrement

Consulte le formulaire d'inscription en bas de la page.

Q11

Remplis le formulaire avec un pseudo et un mot de passe fictifs, puis clique sur « S'inscrire ». Dans l'onglet Réseau, la requête utilise-t-elle GET ou POST ?

Q12

Le mot de passe apparait-il dans l'URL ? Où peut-on le trouver malgré tout dans les outils de développement ?

Q13

Modifie temporairement le formulaire pour passer en method="GET". Que se passe-t-il avec le mot de passe dans l'URL ? Pourquoi est-ce problématique ?

Q14

L'adresse du serveur commence par http://. Est-ce que POST suffit à protéger le mot de passe d'un attaquant qui intercepterait le trafic réseau ? Justifie.

Q15

Quelle modification de l'adresse indiquerait que la transmission est chiffrée ? Comment le navigateur le signale-t-il visuellement ?


Bilan - Schéma à compléter

Complète le schéma suivant. Remplace chaque ___ par le terme qui convient.

sequenceDiagram
    participant N as Navigateur (client)
    participant S as Serveur (Python)

    Note over N: 1. l'utilisateur clique<br/>le code ___ s'exécute
    N->>S: 2. requête ___ vers /deviner<br/>paramètre : ___=___
    Note over S: 3. le serveur ___<br/>la proposition au nombre secret
    S-->>N: 4. réponse ___ : "___"
    Note over N: 5. le code JS modifie le ___<br/>pour afficher le message

Pour aller plus loin

Extension 1

Comment empêcher un utilisateur de tricher en envoyant 999 depuis la console du navigateur ?

Extension 2

Que faudrait-il changer si on voulait que chaque élève joue avec son propre nombre secret, indépendamment des autres ?

Extension 3

Cherche ce qu'est un cookie. Comment pourrait-il résoudre le problème de la question précédente ?