iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
Formations
Node.js / HTML · Débutant

WebSocket

Comprendre le protocole WebSocket de zéro et construire un système de chat complet : connexion, utilisateurs en mémoire, messages privés et groupes — sans base de données.

Node.jswsJavaScriptHTML
01Le protocole WebSocket02Premier serveur WebSocket03Gérer les utilisateurs en mémoire04Chat global et broadcast05Messages privés06Groupes et rooms07Interface client complète
Chapitre 5·20 min

Messages privés

Un message privé ne rejoint qu'une seule personne : le destinataire. L'expéditeur en reçoit une copie pour confirmation. Personne d'autre ne voit rien.

C'est là que le Map de l'étape précédente prend tout son sens : retrouver le socket d'un utilisateur par son nom se fait en O(1).

Le type de message dm (direct message)

server.js
case 'dm':
  handleDM(socket, msg)
  break
server.js
function handleDM(socket, msg) {
  const to = (msg.to || '').trim()
  const content = (msg.content || '').trim()
 
  if (!to || !content) {
    socket.send(JSON.stringify({ type: 'error', content: 'Destinataire ou contenu manquant' }))
    return
  }
 
  if (to === socket.username) {
    socket.send(JSON.stringify({ type: 'error', content: 'Impossible de s\'écrire à soi-même' }))
    return
  }
 
  const target = users.get(to)
  if (!target) {
    socket.send(JSON.stringify({ type: 'error', content: `${to} n'est pas connecté` }))
    return
  }
 
  const message = {
    type: 'dm',
    from: socket.username,
    to,
    content,
    at: new Date().toISOString(),
  }
 
  // Envoyer au destinataire
  target.send(JSON.stringify(message))
 
  // Envoyer une copie à l'expéditeur (confirmation)
  socket.send(JSON.stringify(message))
}

Côté client — traiter les DMs

client.html
ws.onmessage = (event) => {
  const msg = JSON.parse(event.data)
 
  switch (msg.type) {
    case 'chat':
      console.log(`[global] ${msg.from} : ${msg.content}`)
      break
 
    case 'dm':
      const isMine = msg.from === myUsername
      const other = isMine ? msg.to : msg.from
      const direction = isMine ? '→' : '←'
      console.log(`[dm:${other}] ${direction} ${msg.content}`)
      break
 
    case 'system':
      console.log(`--- ${msg.content} ---`)
      break
 
    case 'error':
      console.error('Erreur :', msg.content)
      break
  }
}

Envoyer un DM depuis la console

// Alice envoie un message privé à Bob
ws.send(JSON.stringify({
  type: 'dm',
  to: 'bob',
  content: 'Salut, c\'est privé !'
}))

Alice voit dans sa console :

[dm:bob] → Salut, c'est privé !

Bob voit dans sa console :

[dm:bob] ← Salut, c'est privé !

Carol, si elle est connectée, ne reçoit rien.

Gérer l'utilisateur déconnecté

Si Bob se déconnecte entre le moment où Alice tape son message et le moment où elle l'envoie, users.get('bob') renvoie undefined. Le check if (!target) couvre ce cas et renvoie une erreur claire à Alice.

Notification de lecture (optionnel)

Pour signaler que le destinataire a vu le message, on peut ajouter un acquittement :

server.js
case 'dm_read':
  const sender = users.get(msg.from)
  if (sender) {
    sender.send(JSON.stringify({
      type: 'dm_read',
      by: socket.username,
      at: new Date().toISOString(),
    }))
  }
  break

Le client l'envoie dès qu'il affiche le message :

// Quand on reçoit un DM et qu'on le rend visible :
ws.send(JSON.stringify({ type: 'dm_read', from: msg.from }))

Les DMs fonctionnent. Prochaine étape : les groupes, où plusieurs utilisateurs peuvent rejoindre un canal partagé.

Précédent
Chat global et broadcast
Suivant
Groupes et rooms

Développeur fullstack passionné. J'apprends en construisant et je documente tout — front, back, outils. Le code s'apprend mieux en public.

Naviguer

IndexTous les articlesFormationsProfilOutilsBibliothech

Ailleurs

GitHub RSS

Newsletter

Les articles, libs et découvertes. Une fois par semaine, pas plus.

© 2026 William LoreeConçu & codé à la main