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'étatreadyStatechange.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,
responseTextpartiel disponible. - 4 (terminé) : la réponse complète est disponible.
- 0 (non initialisé) : l'objet n'est pas encore prêt, méthode
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)