REMARQUE ! Les informations sur cette page sont largement obsolètes. Pour obtenir des informations à jour sur le projet Mozilla, consulter la page de la communauté Mozilla francophone, leur blog principal et leur blog technique.
Bien qu'encore balbutiant, l'âge des services Web et de SOAP a déjà créé une demande très variée de technologies client. Une recherche de « client SOAP » donne d'innombrables implémentations pour C++, Perl, .NET, PHP et Java. Si vous creusez un peu plus profondément, vous pouvez même trouver des clients pour des langages comme Ruby, Python et Tcl. La plupart de ces clients opèrent au niveau serveur, comme middleware ou comme composant d'un système plus grand.
Cependant les clients Web sont traditionnellement mis à l'écart, jusqu'à présent la création de messages SOAP et la connexion aux services web convenaient mieux aux applications serveurs spécialement conçus pour ces tâches.
Jusque récemment, c'était vrai. Avec la sortie de Mozilla 1.0, le monde a maintenant un navigateur qui supporte nativement SOAP. Vous n'avez plus besoin de faire des assemblages, l'exécution et le traitement les opérations SOAP incombent seulement au côté serveur. Une application Web s'exécutant dans Mozilla (ou dans un client utilisant le même moteur de script, comme Netscape 7.0) peut maintenant faire des appels SOAP directement du client sans exiger que le navigateur n'ait besoin de faire un rafraîchissement ou des appels supplémentaires au serveur. Les données retournées d'une opération SOAP peuvent être accédées via les même méthodes DOM niveau 2 utilisées pour parcourir un document XML.
Note : les scénarios de script utilisés dans cet article ont été
développés en utilisant Mozilla 1.0 sur un iBook sous Mac OS X.
Seules les plus récentes version de Mozilla incluent l'API SOAP. Pour exécuter
ces scripts, vous devrez copier le code dans un document HTML et l'exécuter
de votre machine en local (voir les informations de sécurité, ci-dessous).
NDT : Les exemples ne fonctionnent pas
dans toutes les versions de Mozilla qui ont suivies la 1.0. En effet une régression
identifiée sous le bogue 202725
générait des erreurs « permission denied » lors de l'appel de la méthode getElementsByTagName
sur une réponse SOAP. Le bogue était
présent dans Mozilla 1.4, mais est corrigé dans Mozilla 1.6a. Je n'ai pas testé les autres versions.
L'API SOAP de Mozilla est une interface JavaScript d'une série d'objets conçus pour créer, envoyer et recevoir des messages SOAP. Ces messages sont codés en XML, mais vous ne devez pas en savoir beaucoup sur la partie XML de SOAP pour utiliser l'API de Mozilla. La construction d'un message SOAP est aussi facile que de créer un autre objet JavaScript.
Un message SOAP de base contient quelques informations clef : l'URI du service cible, le nom de la méthode du service que vous voulez appeler et une série de paramètres à passer en arguments à la méthode. Une fois que ces éléments sont en place, l'appel SOAP est prêt à être exécuté.
J'ai choisi la populaire API Web de Google comme le service SOAP cible pour ces scripts d'exemples. Puisque Google impose des limites d'utilisation de leur API, vous devrez vous procurer une clef gratuite de l'API Google afin que ces scripts puissent accéder complètement aux données de la recherche.
L'invocation de services SOAP via l'API Mozilla peut être faite de façon synchrone ou asynchrone. Un appel SOAP synchrone obligera le script à attendre la réponse du service avant de continuer — un comportement connu comme bloquant. Un appel asynchrone (non bloquant) permettra au au script de continuer sans attendre une réponse, et utilise un « écouteur » ou « listener » (une procédure de rappel ou callback). pour manipuler la réponse du service quand elle arrive. Les scripts d'exemple de cet article utilisent des appels SOAP asynchrones.
Si vous voulez expérimenter différents services en plus de Google, vous pouvez trouver une abondante liste d'adresses de services SOAP sur XMethods.
Parce que l'API SOAP permet au navigateur de faire des appels HTTP à des services que vous (l'utilisateur) ne contrôlez pas, la sécurité de votre système devient un problème. Un navigateur client sécurisé, ne permettra pas par exemple l'exécution de scripts entre les frames si elles contiennent des pages de deux domaines différents. De la même façon il ne permettra pas à un script de faire des appels comportant des risques à un service d'un domaine externe. Après tout, qui sait quel genre du code potentiellement malveillant ce prétendu « service » va retourner ?
Pour assurer la sécurité de votre système, un script utilisant l'API SOAP de Mozilla doit être un script signé ou s'exécuter sur la machine locale de l'utilisateur. (Pour en savoir plus sur les scripts signés de Mozilla voir scripts signés et privilèges : un exemple.) Même en prenant ces précautions, Mozilla exigera que l'utilisateur accorde les privilèges de sécurité appropriés avant d'exécuter le script.
Vous créez un message SOAP tout comme un objet tableau ou image en exécutant script. Un certain nombre d'objets relatifs à SOAP sont disponibles, mais pour le moment vous devrez seulement vous inquiéter de ces quatre :
SOAPCall
:
le coeur de l'opération SOAP, fournit les moyens de coder et envoyer votre message.
SOAPParameter
:
un seul paramètre peut être passé comme un argument à la méthode du service.
Les paramètres multiples sont stockés dans un tableau qui sera donné à l'objet SOAPCALL
.
SOAPResponse
: la réponse du service. Il contient les
résultats de la méthode invoquée par SOAPCALL
.SOAPFault
:
un objet qui représente une erreur ou un avertissement du service.
Les objets SOAPCall
et SOAPParameters
sont les seuls que
vous devrez créer avec JavaScript. SOAPResponse
et
SOAPFault
sont automatiquement produit quand le service
retourne une réponse.
Ainsi quelles méthodes pouvez-vous appeler d'un service web donné ? D'habitude un service fournira un WSDL (encore un autre schéma XML), un fichier décrivant les méthodes disponibles et les paramètres exigés pour les appeler. Un client SOAP intelligent sera capable de faire l'analyse syntaxique de ce fichier et produira automatiquement les interfaces nécessaires pour communiquer avec le service.
Mozilla est intelligent, mais pas encore assez intelligent — son interface WSDL est en cours de developpement. Alors pour le moment nous sommes réduit à lire le fichier WSDL nous-mêmes pour apprendre ce qu'un service peut offrir. Un guide d'initiation sur WSDL pourrait facilement remplir un autre article, donc je vais sauter les détails sanglants et uniquement indiquer les parties appropriées comme nécessaire partout dans cet article. NDT : Depuis Mozilla 1.4, Gecko peut se connecter aux services web utilisant le mandatement WSDL. Un article de DevEdge explique comment faire.
Le fichier WSDL de l'API Web de Google identifie trois méthodes :
doGoogleSearch
, doGetCachedPage
et
doSpellingSuggestion
. De ces trois, je vais me concentrer
sur doGoogleSearch
pour le code d'exemple, mais je laisserai
aussi un peu de place pour les deux autres méthodes. Je commencerai en
définissant une fonction pour créer et envoyer un message SOAP spécialement
conçu pour Google :
function callGoogle(method,params,callback){ }
La fonction callGoogle
exige trois arguments :
method
: une chaîne indiquant la méthode du service que vous voulez appeler.params
: un tableau contenant les objets SOAPParameter
callback
: un pointeur sur la fonction JavaScript qui traitera la
réponse SOAP du service.
callGoogle
utilisera les valeurs de ces trois arguments pour créer
un objet SOAPCall
représentant le message que je veux envoyer.
Avant que vous ne créiez un message SOAP, vous devez permettre à l'utilisateur d'accorder les permissions « UniversalBrowserRead » au script pour pouvoir faire un appel à un service distant. Pour le faire, vous avez besoin d'utiliser le Privilege Manager, intégré d'origine au produit Netscape et au code de Mozilla.
function callGoogle(method,params,callback){ try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); } catch (e) { alert(e); return false; } }
Le code ci-dessus doit se trouver à l'intérieur de la fonction JavaScript ou du bloc de code responsable de lancer l'appel SOAP et doit être avant l'appel lui-même. Quand ce code s'exécute, un message est présenté aux utilisateurs leur demandant d'accorder ou de refuser le privilège :
Cela arrivera chaque fois que la fonction de callGoogle
est invoquée.
Rappelez-vous que l'on peut seulement accorder ce privilège à un script signé ou s'exécutant sur la machine locale. Autrement, le code générera l'erreur « enablePrivilege not granted » l'appel de SOAP ne sera pas exécuté.
Une fois que l'on a donné au script la permission de s'exécuter, le travail suivant
est de créer un objet SOAPCall
:
function callGoogle(method,params,callback){ try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); } catch (e) { alert(e); return false; } var soapCall = new SOAPCall(); soapCall.transportURI = "http://api.google.com/search/beta2"; }
La propriété transportURI
de l'objet SOAPCall
est
une chaîne indiquant l'URI du point final du service. Vous pouvez le trouver
vers la fin du fichier WSDL de Google, dans l'élément <service/>
.
NDT : Le fichier WSDL de Google
se nomme GoogleSearch.wsdl et peut être téléchargé dans l'archive suivante
proposée par Google.
Ensuite, le message doit être codé avec la méthode requise en lui fournissant
les paramètres. Cela est fait en passant les arguments suivants à la méthode de codage
de l'objet SOAPCall
:
soapCall.encode(0, method, "urn:GoogleSearch", 0, null, params.length, params);
Le code ci-dessus n'est pas évident à décrire parce que certains des arguments
ne sont pas nécessaires pour les opérations SOAP de base et ont donc des valeurs
zéro et nulles. Les seuls arguments pour lesquels vous êtes concernés sont
method
, qui est la méthode du service à être invoqué et l'espace
de nom du service cible du service (dans notre cas, l'espace de noms
"urn: GoogleSearch"
, peut être trouvé dans le fichier WSDL
en tant que valeur de l'attribut de targetNamespace
,
de l'élément <definitions/>
).
Les deux derniers arguments donnés à la méthode de codage sont respectivement le nombre de paramètres passé à la méthode du service et le tableau des paramètres.
Maintenant vous êtes prêts à invoquer SOAPCall
et envoyer
la requête au service Google. La méthode asyncInvoke
de
l'objet SOAPCall
prend un argument : un pointeur sur
une fonction de rappel (callback)
qui traitera la réponse SOAP.
Comme noté ci-dessus, la fonction de callGoogle
exige une
fonction de rappel comme troisième argument, mais je ne suis pas prêt
à utiliser tel quel. Au lieu de cela, je vais faire une petite
vérification d'erreur avant de remettre la réponse à la suite de
l'application. Donc je le passerai à handleSOAPResponse
:
function callGoogle(method,params,callback) { try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); } catch (e) { alert(e); return false; } var soapCall = new SOAPCall(); soapCall.transportURI = "http://api.google.com/search/beta2"; soapCall.encode(0, method, "urn:GoogleSearch", 0, null, params.length, params); soapCall.asyncInvoke( function (response, soapcall, error) { var r = handleSOAPResponse(response,soapcall,error); callback(r); } ); }
La dernière partie de cet exemple exige un peu plus d'explication.
Quand la fonction de rappel passée est exécutée par asyncInvoke
,
on lui donne trois arguments qui proviennent du résultat retourné par
l'appel SOAP :
response
: un objet SOAPResponse
contenant les données retournées du service.soapcall
: un pointeur sur l'objet original SOAPCall
responsable de ce message. C'est utile si vous avez plusieurs objets SOAPCall
en utilisation et que vous devez les différencier entre eux à l'intérieur d'une seule
et même fonction de rappel.error
: un code de retour. Une valeur autre que zéro indique une erreur.
Puisque vous voulez que la réponse aille à handleSOAPResponse
pour la vérification d'erreur
et ensuite à la fonction de rappel initialement donnée à callGoogle
, vous devez
envelopper les deux descripteurs dans une fonction anonyme passée à la méthode asyncInvoke
.
Rappelez-vous qu'asyncInvoke
n'attend pas une réponse du service avant de permettre
au script de continuer. Cette manière de faire assure que le script n'oublie pas la fonction de rappel
initiale lorsque la fonction callGoogle
se termine.
Bien, vous avez terminé la fonction callGoogle
qui assemble et envoie les messages
SOAP
à Google. Maintenant il est temps d'utiliser handleSOAPResponse
pour s'occuper de la réponse.
La fonction handleSOAPResponse
reçoit les résultats de l'appel de SOAP et
les vérifie pour s'assurer qu'il n'y a pas d'erreur SOAP
(NDT : Les éléments Fault
des enveloppes SOAP)
ou d'erreur du service. Si aucune erreur SOAP ou erreur de service n'est trouvée, le script
suppose que la réponse est valide et passe le SOAPResponse
à la fonction
de rappel initialement donnée par l'utilisateur à callGoogle
.
La première étape est de voir si l'argument erreur contient une valeur autre que zéro. S'il c'est le cas nous pouvons supposer qu'une erreur fatale est arrivée et quitter le script :
function handleSOAPResponse (response,call,error) { if (error != 0) { alert("Service failure"); return false; } }
Si aucune erreur n'est trouvée ici, le script continue à vérifier qu'il n'existe pas d'erreur SOAP.
Une erreur SOAP se produit habituellement lorsque quelque chose
s'est vraiment mal passé pendant l'appel : un paramètre manquant,
une méthode invalide, etc. Quand une telle erreur se produit, un objet
SOAPFault
est généré qui
contient l'information sur ce qui a mal tourné pendant l'opération SOAP.
Pour tester SOAPFault
, le script doit vérifier la propriété
fault de l'objet SOAPResponse
. Si aucune erreur
ne s'est produite, la valeur de cette propriété sera nulle. Autrement,
c'est un objet SOAPFault
.
Un objet SOAPFault
a les propriétés suivantes :
faultCode
: le code numérique de la faute.faultString
: une chaîne, contenant d'habitude un message d'erreur.faultNamespaceURI
: l'URI d'espace de noms de l'erreur.element
: un pointeur sur le noeud
DOM du message XML SOAP
représentant l'erreur.detail
: un autre pointeur sur un noeud DOM
contenant les détails de l'erreur.
La fonction handleSOAPResponse
ci-dessous utilise faultCode
et faultString
pour avertir l'utilisateur qu'une erreur s'est produite.
Si vous désirez, vous pouvez changer les messages d'avertissement ou ajouter du
code pour fournir un comportement supplémentaire dans le cas d'une erreur.
function handleSOAPResponse (response,call,error) { if (error != 0) { alert("Service failure"); return false; } else { var fault = response.fault; if (fault != null) { var code = fault.faultCode; var msg = fault.faultString; alert("SOAP Fault:\n\n" + "Code: " + code + "\n\nMessage: " + msg ); return false; } else { return response; } } }
Notez que dans le cas d'une erreur SOAP ou d'une erreur de service, une valeur
false est retournée à la fonction de rappel spécifié dans
callGoogle
. Si la réponse passe ces vérifications, le script
retourne le SOAPResponse
complet à la fonction de rappel.
Je vais faire marche arrière pendant un instant et regarder comment utiliser
la fonction callGoogle
pour faire un appel SOAP.
D'abord, vous devez préparer un tableau de paramètres exigés par la méthode du
service. Comme mentionné plus haut, l'API Web de Google fournit trois méthodes.
Une d'entre elle, doSpellingSuggestion
, exige deux paramètres :
le mot ou l'expression que vous voulez vérifier et une clef d'API Google.
Le deuxième argument exigé par callGoogle
est un tableau contenant
les paramètres nécessaires pour faire l'appel. Ceci se fait facilement avec le
constructeur SOAPParameter
, qui exige deux arguments : dans
l'ordre, la valeur et nom du paramètre à ajouter.
// crée le paramètre tableau var params = new Array(); // remplacer 'yourKeyHere' par votre clé Google params[0] = new SOAPParameter(yourKeyHere, "key"); params[1] = new SOAPParameter("brintey speers","phrase"); // maintenant on fait l'appel au service Google callGoogle("doSpellingSuggestion",params,parseResult);
Voici un exemple plus complexe pour la méthode doGoogleSearch
:
var p = new Array(); p[0] = new SOAPParameter(yourKeyHere, "key"); p[1] = new SOAPParameter("Mozilla", "q"); // la chaîne recherchée p[2] = new SOAPParameter(0, "start"); p[3] = new SOAPParameter(10, "maxResults"); p[4] = new SOAPParameter(false, "filter"); p[5] = new SOAPParameter("", "restrict"); p[6] = new SOAPParameter(false, "safeSearch"); p[7] = new SOAPParameter("", "lr"); p[8] = new SOAPParameter("Latin-1", "ie"); p[9] = new SOAPParameter("Latin-1", "oe"); callGoogle("doGoogleSearch" ,p, parseResult);
Dans le code ci-dessus, parseResult
est la fonction de rappel que nous
voulons voir gérer le traitement d'une opération SOAP pleinement réussie (sans erreur SOAP, ni
erreur de service). Puisque la fonction handleSOAPResponse
s'occupe de la vérification d'erreur, vous ne devez pas vous en inquiéter
dans votre fonction de rappel. Si une erreur de service ou une erreur SOAP sont
trouvées, la valeur retournée à parseResult
sera simplement
false.
Le dernière partie de notre puzzle est réalité d'écrire la fonction de rappel
parseResult
pour traiter la réponse SOAP. Le premier travail est
de voir si le résultat remis à parseResult
après une opération SOAP
est vraiment un objet SOAPResponse
:
function parseResult(result) { if (result == false) { return; } }
Le script ci-dessus sort sans avertissement si aucun SOAPResponse
n'est disponible. Une implémentation plus efficace fournirait une alerte ou
un comportement supplémentaire.
Maintenant vous pouvez récupérer l'information retournée de la méthode du
service SOAP. L'approche la plus directe est d'utiliser la méthode
getParameters
de l'objet SOAPResponse
. Comme
vous auriez pu le deviner, getParameters
retourne un
tableau contenant les paramètres retournés par le service SOAP.
function parseResult(result) { if (result == false) { return; } var num = new Object(); var params = result.getParameters(false,num); }
L'appel à getParameters
exige deux arguments :
un booléen à false (indiquant que c'est un message de style
RPC)
et un objet JavaScript générique num
, qui contiendra
le nombre de paramètres à retourner.
Le nombre de paramètres retourné dépend du service et doit être décrit
dans le fichier WSDL. Dans le cas de Google, les trois méthodes
du service retournent un seul paramètre comme réponse. Dans le
fichier WSDL de Google, conformément aux <message/>
,
vous pouvez voir que le paramètre est dans les trois cas un seul élément
return
.
La recherche des données du service est maintenant une simple question d'analyse syntaxique des paramètres. Chaque paramètre dans le tableau a les propriétés suivantes :
name
: le nom du paramètre.value
: la valeur du paramètre.element
: un pointeur sur le noeud du DOM du message XML SOAP retourné
représentant le paramètre.
Mettons ces connaissances en pratique. Puisque le doSpellingSuggestion
retourne uniquement un paramètre contenant l'orthographe suggérée, vous pouvez
vous référer directement à la propriété value
du paramètre pour
récupérer la suggestion :
function parseResult(result) { if (result==false) { return; } var num = new Object(); var params = result.getParameters(false,num); var suggestion = params[0].value; alert("Suggested spelling: " + suggestion); }
Alternativement, vous pouvez utiliser le DOM pour récupérer
l'information via la propriété element
du paramètre :
var suggestion = params[0].element.firstChild.nodeValue;
La possibilité d'utiliser le DOM est de cette façon est particulièrement utile
quand les paramètres retournent un XML complexe plutôt qu'une simple paire
noms/valeur. Un exemple est la méthode du service doGoogleSearch
,
qui fournit non seulement une information conséquente sur les résultats de la recherche,
mais aussi des méta-informations concernant le temps de recherche, le nombre total de
résultats et le filtrage. Par exemple, en recevant une réponse du service
de recherche de Google, vous pouvez vouloir récupérer uniquement les noms et
les tailles des fichiers en cache des documents correspondants. Avec le DOM,
c'est assez simple :
function showResults(results) { if (!results) { return; } var params = results.getParameters(false,{}); var matches = params[0].element.getElementsByTagName("item"); var str = ""; for (var i=1;i < matches.length;i++) { var URL = matches[i].getElementsByTagName("URL").item(0).firstChild; var title = matches[i].getElementsByTagName("title").item(0).firstChild; var cache = matches[i].getElementsByTagName("cachedSize").item(0).firstChild; str += "<a href=\"" + URL.nodeValue + "\">" + title.nodeValue + "</a> (" + cache.nodeValue + ")<br/>"; } document.body.innerHTML = str; }
Vous pouvez télécharger l'exemple complet que j'ai réalisé qui fonctionne, fait pour l'API de Google :
Cela couvre le processus entier, de la définition des paramètres à l'exécution de l'appel de SOAP à l'analyse syntaxique et l'affichage des résultats de recherche avec des méthodes du DOM. Allez-y expérimentez ce code et écrivez vos propres interfaces à d'autres services SOAP et créez en utilisant les données retournées dans vos applications Web.
En regardant au-delà du navigateur, le moteur de script fait partie du paquet Mozilla complet, donc il est possible d'écrire en XUL (Le langage d'interface utilisateur XML, avec lequel l'interface de Mozilla est construite) les applications qui profitent de la même API. L'API SOAP de Mozilla vous permet d'utiliser des standards web familiers — JavaScript et le DOM — pour intégrer facilement des services Web dans vos applications côté client.
(Site mise à jour le mardi 16 mars 2004)