Techniques de Communication Web et Stratégies d'Origine Croisée

1. Méthodes de Communication entre Front-End et Back-End

  • Ajax
  • WebSocket
  • CORS

2. Création d'une Requête Ajax

Le principe repose sur l'utilisation de l'objet XMLHttpRequest pour envoyer des requêtes asynchrones au serveur, récupérer les données, puis mettre à jour le DOM. Cet objet constitue la base de la communication Ajax.

Propriétés clés de XMLHttpRequest :

  • onreadystatechange : déclenché chaque fois que l'état readyState change.
  • readyState : représente l'état de la requête, variant de 0 à 4 :
    • 0 (non initialisé) : l'objet n'est pas encore prêt, méthode open() non appelée.
    • 1 (connexion établie) : la requête est envoyée après appel de open().
    • 2 (requête reçue) : l'envoi est terminé, les en-têtes sont reçus.
    • 3 (traitement en cours) : le serveur traite la réponse, responseText partiel disponible.
    • 4 (terminé) : la réponse complète est disponible.
  • status : code de statut HTTP retourné par le serveur.
  • responseText : réponse sous forme de chaîne.
  • responseXML : réponse sous forme de document XML.

Exemple de fonction Ajax encapsulée :

function effectuerRequete(config) {
    let parametres = {
        url: '',
        methode: 'GET',
        donnees: {},
        onSuccess: function() {},
        onError: function() {}
    };
    for (let cle in config) {
        parametres[cle] = config[cle];
    }
    if (parametres.url) {
        let requete = new XMLHttpRequest();
        let corpsRequete = [];
        for (let cle in parametres.donnees) {
            corpsRequete.push(encodeURIComponent(cle) + '=' + encodeURIComponent(parametres.donnees[cle]));
        }
        let urlRequete = parametres.url;
        if (parametres.methode.toUpperCase() === 'GET') {
            urlRequete += '?' + corpsRequete.join('&');
            requete.open('GET', urlRequete, true);
            requete.send();
        } else if (parametres.methode.toUpperCase() === 'POST') {
            requete.open('POST', urlRequete, true);
            requete.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            requete.send(corpsRequete.join('&'));
        }
        requete.onreadystatechange = function() {
            if (requete.readyState === 4) {
                if (requete.status === 200 || requete.status === 304) {
                    let reponse = requete.responseText;
                    if (typeof parametres.onSuccess === 'function') {
                        parametres.onSuccess(reponse);
                    }
                } else {
                    if (typeof parametres.onError === 'function') {
                        parametres.onError();
                    }
                }
            }
        };
    }
}

Utilisation :

effectuerRequete({
    url: '/api/donnees',
    methode: 'POST',
    donnees: { id: 'abc', nom: 'test' },
    onSuccess: function(resultat) {
        console.log('Succès :', resultat);
    },
    onError: function() {
        console.log('Échec de la requête');
    }
});

Question d'entretien : Implémenter une requête Ajax simplifiée avec Promise

function requeteAvecPromise(url, methode = 'GET') {
    return new Promise((resolution, rejet) => {
        let xhr = new XMLHttpRequest();
        xhr.open(methode, url, true);
        xhr.onload = function() {
            if (xhr.status >= 200 && xhr.status < 300) {
                resolution(JSON.parse(xhr.responseText));
            } else {
                rejet(new Error('Statut de réponse : ' + xhr.status));
            }
        };
        xhr.onerror = function() {
            rejet(new Error('Erreur réseau'));
        };
        xhr.send();
    });
}
// Exemple d'utilisation
requeteAvecPromise('/fichier.json', 'GET')
    .then(data => console.log(data))
    .catch(erreur => console.error(erreur));

3. Politique d'Origine (Same-Origin Policy)

Définition

Deux URLs sont considérées comme « de même origine » si elles partagent le même protocole, le même domaine et le même port. Toute différence entraîne une origine croisée.

But

Cette politique vise à protéger les données utilisateur en empêchant les sites malveillants d'accéder aux informations d'autres origines.

Restrictions

Pour les requêtes entre origines différentes, les limitations suivantes s'appliquent :

  • Les cookies et le localStorage ne sont pas accessibles.
  • L'accès au DOM est bloqué.
  • Les réponses des requêtes Ajax sont retenues par le navigateur, bien que la requête puisse être envoyée.

Points importants :

  • La restriction d'origine s'applique uniquement côté client ; le serveur n'a pas cette contrainte.
  • Les balises comme <img>, <link> et <script> peuvent charger des ressources d'origines différentes.

4. Solutions pour les Problèmes d'Origine Croisée

Partage de Cookies

Condition : Les deux pages web partagent le même domaine de premier niveau.

Méthode : Définir document.domain sur le domaine parent commun.

Exemple : Pour partager des cookies entre http://sous.example.com/a.html et http://autre.example.com/b.html, définir document.domain = 'example.com'; dans les deux pages.

Accès au DOM via Iframes

Condition : Similaire au partage de cookies, avec des iframes imbriquées.

Méthode : Utiliser document.domain pour harmoniser l'origine.

Exemple : Une page parente et une iframe enfant peuvent accéder mutuellement à leurs DOM après avoir défini document.domain sur le domaine commun.

Communication entre Iframes

Méthode Hash

Principe : Transmettre des données via le fragment d'URL (après le #) et écouter l'événement hashchange.

Condition : Communication entre une page et une iframe d'origine différente.

Exemple : La page parente modifie l'URL de l'iframe enfant avec des données dans le hash, et l'enfant détecte le changement.

Méthode postMessage

Principe : Utiliser l'API window.postMessage pour une communication sécurisée entre fenêtres.

Condition : Communication entre iframes ou fenêtres d'origines différentes.

Exemple : La page parente envoie un message à l'iframe enfant avec postMessage, et l'enfant écoute l'événement message pour le récupérer.

Solutions pour les Requêtes Ajax

JSONP

Principe : Exploiter la capacité des balises <script> à charger des ressources d'origines différentes. Le serveur encapsule les données dans une fonction de rappel spécifiée par le client.

Limitation : Uniquement pour les requêtes GET.

Exemple : Créer dynamiquement un élément <script> avec une URL incluant un paramètre callback, et définir la fonction de rappel pour traiter les données.

CORS (Cross-Origin Resource Sharing)

Principe : Le serveur ajoute des en-têtes de réponse spécifiques pour autoriser les requêtes d'origines croisées.

Pour les requêtes simples : L'en-tête Access-Control-Allow-Origin est renvoyé par le serveur.

Pour les requêtes compleexs : Une requête préliminaire (preflight) est envoyée avec la méthode OPTIONS, et le serveur répond avec des en-têtes comme Access-Control-Allow-Methods, Access-Control-Allow-Headers, etc.

Exemple de configuration serveur avec Express.js :

const express = require('express');
const app = express();

// Middleware pour les requêtes CORS simples
app.use((requete, reponse, suivant) => {
    reponse.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
    suivant();
});

// Gestion des requêtes OPTIONS pour CORS complexe
app.options('/ressource', (requete, reponse) => {
    reponse.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
    reponse.setHeader('Access-Control-Allow-Methods', 'GET, POST');
    reponse.setHeader('Access-Control-Allow-Headers', 'Content-Type');
    reponse.setHeader('Access-Control-Max-Age', '86400');
    reponse.status(204).send();
});

app.get('/ressource', (requete, reponse) => {
    reponse.json({ message: 'Données autorisées' });
});

Utilisation de la bibliothèque cors pour simplifier la configuration :

const cors = require('cors');
app.use(cors({
    origin: 'http://localhost:3000',
    methods: ['GET', 'POST'],
    allowedHeaders: ['Content-Type']
}));

5. Outils Courants pour les Requêtes Ajax

  • jQuery (pour les projets anciens)
  • Fetch API (standard moderne)
  • Axios (bibliothèque populaire avec support étendu)

Étiquettes: AJAX WebSocket CORS JSONP Politique-meme-origine

Publié le 23 juillet à 02h05