Utiliser JSON comme format de données de retour d'une requête Ajax

16 janvier 2007Ajax, JSON, XMLHttpRequest
 Cet article a été rédigé il y a plusieurs années et peut ne plus être tout à fait à jour…

AJAX[1] est une méthode permettant d'envoyer des requêtes en arrière-plan à un serveur, généralement en vue d'obtenir des données en réponse...

Et qui dit données dit format de données... Voire même, comme ici, format d'échange de données.

XML vs JSON

De par la définition même d'AJAX, le format d'échange de données utilisé à l'origine pour les requêtes Ajax est le XML.

XML

XML présente de nombreux avantages, dont :

  • C'est un format texte, donc, lisible par n'importe qui - contrairement à un format binaire, qui nécessite un logiciel de décodage.
  • C'est un format structuré : les données peuvent être imbriquées, pour former des schémas complexes, à même de répondre à la plupart des besoins.
  • C'est un format largement répandu : il est possible de créer, lire, et manipuler un document XML dans le très nombreux langages.
  • C'est un format ouvert : sa spécification est librement accessible par tous.

Mais créer un document XML est complexe et lourd... De même que le lire par la suite.
Souvenez-vous de l'exemple que j'avais donné à propos de la propriété responseXML de l'objet XMLHttpRequest...

JSON

D'un autre côté, lorsque nous utilisons de l'Ajax pour échanger des informations entre un script côté client et un serveur, le script côté client est généralement programmé en JavaScript... Alors, pourquoi ne pas employer un format de données plus facilement utilisable en JavaScript ?

Ce qui compte, finalement, c'est de conserver les avantages que nous avons présenté plus haut pour le XML.


Pour information, voici quelques liens traitant de "JSON vs XML" :

Quelques rappels concernant JSON

Pour commencer, je vous conseille de jeter un coup d'oeil sur mon article "JSON - JavaScript Object Notation : Présentation", qui vous permettra de comprendre ce qu'est JSON, en insistant sur la notion de JSON valide.

En résumant très rapidement, JSON est un format que l'on peut utiliser pour représenter des objets sous forme d'une chaîne de caractères, en utilisant une notation compatible avec JavaScript.

Les types de données que JSON accepte sont numérique (18, 45.25), chaînes de caractères ("Hello World!"), booléens (true, false), tableaux, objets, et null.
Attention : les chaînes de caractères doivent être entourées de guillemets doubles.

Pour vous assurer de la validité d'une chaîne JSON avant de l'évaluer, vous pouvez utiliser le code suivant :

var monObjet = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
             text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
         eval('(' + text + ')');

monObjet vaudra false si la chaîne text n'était pas du JSON valide ; la donnée attendue sinon.

Requête Ajax ; JSON en retour

Nous nous baserons sur un exemple simple :

  • Lors du clic sur un lien d'une page HTML, une requête Ajax est envoyée vers un programme PHP.
  • Celui-ci renvoi une liste de couples nom/prénom.
  • A la réception de cette liste par le client, les noms et prénoms sont extraits en JavaScript et placés dans une chaîne de caractères.
  • Cette chaîne de caractères sera alors affichée au sein d'un bloc du document HTML.

Document HTML

Pour commencer, voici notre document HTML :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
    <title>AJAX : Exemple de client</title>
    <script type="text/javascript" src="test1.js"></script>

</head>
<body>
    <p>
        <a href="" onclick="gestionClic(); return false;">
            Cliquez ici !
        </a>
    </p>

    <div id="resultat">&nbsp;</div>

</body>
</html>

Un clic sur le lien provoque l'appel d'une fonction JavaScript.
Un div ayant pour id resultat est présent, pour accueillir le résultat[2].

Un programme côté serveur

Côté serveur, nous utilisons un programme qui renvoi une liste de trois couples nom/prénom, au format JSON :

<?php
    header('Content-Type: text/html; charset: UTF-8');

    $str = <<<STR
[
    {"nom": "Lerdorf", "prenom": "Rasmus"},
    {"nom": "Gutmans", "prenom": "Andi"},
    {"nom": "Suraski", "prenom": "Zeev"}
]
STR;

    echo $str;

?>

Dans un cas réel, ces données pourraient être issues d'une base de données, et la sortie serait générée dynamiquement.

Notons :

  • Il s'agit d'une liste (les délimiteurs sont des crochets "[" et "]").
  • Cette liste contient trois objets (délimités par des accolades "{" et "}")
  • Chaque objet a deux propriétés : nom et prenom, qui correspondent chacune à une chaîne de caractères.
  • Toutes les chaînes de caractères sont délimitées par des guillemets doubles.

JavaScript côté client

Côté client, nous utilisons toujours la même fonction pour créer une instance d'objet XMLHttpRequest :

function createRequestObject()
{
    var http;
    if (window.XMLHttpRequest)
    { // Mozilla, Konqueror/Safari, IE7 ...
        http = new XMLHttpRequest();
    }
    else if (window.ActiveXObject)
    { // Internet Explorer 6
        http = new ActiveXObject("Microsoft.XMLHTTP");
    }
    return http;
} // createRequestObject()

(Et il manque toujours une gestion d'erreur à cette fonction - encore une fois, c'est laissé à votre charge)

Pour valider les données renvoyées, et les evaluer s'il s'agit de JSON valide, nous utiliserons la fonction suivante :

function validateJSON(jsonText)
{
    return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                jsonText.replace(/"(\\.|[^"\\])*"/g, '')))
           && eval('(' + jsonText + ')');
} // validateJSON(jsonText)

Et voici la fonction qui sera déclenchée lors du clic sur le lien :

function gestionClic()
{
  var http = createRequestObject();
  http.open('GET', './test1.php', true);
  http.onreadystatechange = (function ()
    {
      if (http.readyState == 4)
      {
        if (http.status == 200)
        {
          var personnes = validateJSON(http.responseText);
          if (personnes !== false)
          {
            var str = '';
            for (var i in personnes)
            {
              var personne = personnes[i];
              str += personne.prenom + ' ' + personne.nom + '<br />';
            }
            document.getElementById('resultat').innerHTML = str;
          }
          else
          {
            document.getElementById('resultat').innerHTML = "JSON invalide";
          }
        }
        else
        {
          alert('Pas glop pas glop');
        }
      }
    });
  http.send(null);
} // gestionClic()

La gestion de l'appel Ajax et de son retour sont toujours les mêmes ; vous pouvez lire l'article Ajax : un premier appel avec l'objet XMLHttpRequest pour plus d'informations.

Par contre, l'utilisation des données retournées est un peu différente : une fois que nous avons evalué la chaîne de caractères retournée par le serveur, nous disposons d'un objet JavaScript utilisable en natif, sans avoir à utiliser les fonctions de manipulation du DOM auxquelles nous avons du faire appel lorsque nous travaillions avec du XML.

C'est là toute la force de JSON utilisé comme format d'échange de données par rapport à XML, pour les appels Ajax : la simplicité de manipulation des données.

JSON et réponse HTTP

Au sein d'une réponse HTTP, les données au format JSON peuvent être placées en deux endroits :

  • Dans le corps de la page
  • Dans les en-têtes HTTP de la page

Les deux pratiques existent, et se trouvent fréquemment.

Données JSON dans le corps de la page

Placer les données JSON dans le corps de la page est le plus simple : c'est ce que nous avons fait un peu plus haut :

<?php
    header('Content-Type: text/html; charset: UTF-8');
    $str = '[{"nom": "Lerdorf", "prenom": "Rasmus"}, {"nom": "Gutmans", "prenom": "Andi"}, {"nom": "Suraski", "prenom": "Zeev"}]';
    echo $str;
?>

Et récupérer la chaîne JSON côté JavaScript consiste simplement en la lecture de la propriété responseText de l'objet XHR, lorsque sa propriété readyState vaut 4 - c'est-à-dire lorsque les données ont été totalement reçues depuis le serveur :

var strJSON = http.responseText;
alert(strJSON);

Données JSON et en-tête X-JSON

L'autre solution est de placer les données JSON dans un en-tête HTTP, plutôt que dans le corps de la réponse.
Cette méthode est utilisée par certaines bibliothèques JavaScript (Je pense à prototype.js, notamment).

L'en-tête généralement utilisé est "X-JSON".

Du côté du programme serveur, on utilise par exemple, en PHP :

<?php
    header('Content-Type: text/html; charset: UTF-8');
    $str = '[{"nom": "Lerdorf", "prenom": "Rasmus"}, {"nom": "Gutmans", "prenom": "Andi"}, {"nom": "Suraski", "prenom": "Zeev"}]';
    header('X-JSON: ' . $str);
?>

Et côté JavaScript, lors de la récupération de la réponse, on ne lit plus le corps de la réponse, mais l'en-tête X-JSON, en utilisant la méthode getResponseHeader :

var strJSON = http.getResponseHeader('X-JSON');
alert(strJSON);

Un avantage est que vous pouvez aussi renvoyer un message en corps de page... Par exemple, un message qui sera affiché par le navigateur si un visiteur accède directement à l'URL de la page appelée via la requête Ajax.
(Mais est-ce que vous ne devriez pas, par sécurité, gérer ce cas au sein du programme ?)

JSON et langages côté serveur

Avant de terminer, quelques mots sur la génération - et la lecture - de données au format JSON, côté serveur...
JSON est un format textuel, ce qui facilite grandement l'encodage et le décodage de données... Et sa simplicité d'utilisation en JavaScript en fait un format de choix pour les échanges de données à travers des requêtes Ajax.

Cela dit, JSON est un format d'échange de données relativement jeune ; il n'est donc pas encore fréquemment incorporé dans les langages de programmation ou les librairies fournies en "standard" avec ceux-ci.
Par exemple, les fonction json_encode et json_decode ne sont présentes en PHP que depuis la version 5.2, qui est loin d'être répandue, au moment où j'écris ceci.

Mais il existe des bibliothèques permettant de lire/écrire des données au format JSON dans de nombreux langages de programmation. Vous en trouverez une liste importante en bas de la page d'accueil du site json.org.


J'espère que cet article vous aura montré la simplicité de JSON par rapport à XML ; a l'avenir, nous aurons l'occasion de mettre en pratique ce que nous venons de voir, que ce soit en utilisant des bibliothèques de fonctions intégrant l'utilisation de JSON, ou, tout simplement, pour sa facilité d'usage.

Notes

[1] AJAX en majuscules, puisqu'on parle de XML

[2] En ayant déjà un div destiné à contenir le résultat dans notre document HTML de base, nous n'aurons par à le créer dynamiquement en JavaScript, ce qui allégera notre exemple