Il est possible d'effectuer des requêtes HTTP vers un serveur web en lui passant des paramètres, que ce soit par la méthode GET ou par la méthode POST. On peut simuler en javascript ce que l'on peut faire avec un formulaire HTML (balise « form » avec l'attribut « method » à "GET" ou "POST").
Voir le détail sur les ApplisWeb/MethodesRequetesHttp
Cet objet en Javascript sous Mozilla nous permet d'envoyer une requête HTTP. Il dispose de plusieurs méthodes et propriétés pour contrôler l'envoi de la requête et la récupération que l'on reçoit en retour.
Pour les détails de cet objet, voir Reference/Javascript/XmlHttpRequest.
Pour un envoi simple d'une requête HTTP en synchrone (c'est-à-dire que le script Javascript attende de recevoir la réponse avant de continuer), voici le principe :
Voyons ce que cela donne avec les différentes méthodes HTTP.
Notre script ressemblera à ceci :
p = new XMLHttpRequest();
p.onload = null;
p.open("GET", "http://monsite.tld/mon_fichier.xml", false);
p.send(null);
if ( p.status != "200" )
{
alert("Réception erreur " + p.status);
}
else
{
contenu = p.responseText;
// traitement du contenu
}
Ici, nous interrogeons le serveur Web, en lui demandant l'url « http://monsite.tld/mon_fichier.xml » qui correspondant à un fichier XML. Comme c'est une méthode GET, il n'y a pas d'entête à spécifier (donc pas d'appel à setRequestHeader). Après envoi, on récupère le code de retour. Si il vaut 200, c'est que tout s'est bien passé. On peut alors récupérer le contenu de la réponse (donc ici, le contenu du fichier « mon_fichier.xml ») et ensuite le traiter (en faisant appel au DOM par exemple).
Remarquez le premier paramètre à open indiquant le type de la méthode : ici "GET".
On pourrait aussi faire :
p.open("GET", "http://monsite.com/mon_script.php?param1=val1¶m2=val2", false);
Et mon_script.php renverrait un contenu HTML ou XML. Il peut récupérer les paramètres dans le tableau PHP $_GET.
Quelques différences avec la méthode « GET » :
p = new XMLHttpRequest();
p.onload = null;
p.open("POST", "http://monsite.tld/mon_script.php", false);
p.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var corps = "param1=val1¶m2=val2";
p.send(corps);
if ( p.status != "200" )
{
alert("Réception erreur " + p.status);
}
else
{
contenu = p.responseText;
// traitement du contenu
}
Ici donc, à l'appel de la méthode open, on indique la méthode HTTP « POST ». On spécifie le type MIME du contenu du corps de la requête qui sera de simples valeurs encodées : application/x-www-form-urlencoded.
Ensuite on construit le corps de la requète (variable corps). Remarque : il faut encoder les valeurs et les noms des paramètres, grâce à la fonction escape(), pour « échapper » certains caractères.
On envoie ensuite le corps de la requête avec send. Et enfin, on traite la réponse comme dans GET. « » Dans l'exemple, on appelle un script PHP. Celui-ci peut récupérer les paramètres dans le tableau PHP $_POST.
Là, ça devient du sport et il est important de bien respecter le protocole HTTP. Dans l'exemple qui suit, nous allons émuler le formulaire suivant :
<form enctype="multipart/form-data" action="page.php" method="post">
<input type="hidden" name="addfile" value="1">
<input type="file" name="filename" />
<input type="submit" value="Add" />
</form>
Ce formulaire est composé d'un champ de téléversement de fichier et d'un paramètre de type hidden (caché). Reportez-vous à la page ApplisWeb/MethodesRequetesHttp pour connaitre la requête exacte que l'on va devoir envoyer.
La méthode send accepte plusieurs types de paramètres qui sont :
Le but du jeu va donc d'être de créer notre requête en mettant tout dans un « InputStream ».
/*
* Je pars du principe que vous savez créer des objets XPCOM en Javascript
* et que vous avez déja un objet de type « File ».
* Une façon simple d'en obtenir un est d'utiliser l'objet « FilePicker »
* (boite de dialogue de séléction de fichier) comme suit :
*/
var nsIFilePicker = Components.interfaces.nsIFilePicker;
var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
fp.init(window, "Sélectionnez un fichier", nsIFilePicker.modeOpen);
var res = fp.show();
dump("Le fichier " + fp.file.leafName + " a été selectionné et pèse " + fp.file.fileSize + "\n");
const BOUNDARY = "111222111"; //ce qui va nous servir de délimiteur
const MULTI = "@mozilla.org/io/multiplex-input-stream;1";
const FINPUT = "@mozilla.org/network/file-input-stream;1";
const STRINGIS = "@mozilla.org/io/string-input-stream;1";
const BUFFERED = "@mozilla.org/network/buffered-input-stream;1";
const nsIMultiplexInputStream = Components.interfaces.nsIMultiplexInputStream;
const nsIFileInputStream = Components.interfaces.nsIFileInputStream;
const nsIStringInputStream = Components.interfaces.nsIStringInputStream;
const nsIBufferedInputStream = Components.interfaces.nsIBufferedInputStream;
/* 1 */
var mis = Components.classes[MULTI].createInstance(nsIMultiplexInputStream);
/* 2 */
var fin = Components.classes[FINPUT].createInstance(nsIFileInputStream);
fin.init(fp.file, 0x01, 0444, null); //fic est un objet de type fichier
var buf = Components.classes[BUFFERED].createInstance(nsIBufferedInputStream);
buf.init(fin, 4096);
/* 3 */
var hsis = Components.classes[STRINGIS].createInstance(nsIStringInputStream);
var sheader = new String();
sheader += "--" + BOUNDARY + "\r\nContent-disposition: form-data;name=\"addfile\"\r\n\r\n1";
sheader += "\r\n" + "--" + BOUNDARY + "\r\n"
sheader += "Content-disposition: form-data;name=\"filename\";filename=\"" + fp.file.leafName + "\"\r\n";
sheader += "Content-Type: application/octet-stream\r\n";
sheader += "Content-Length: " + fp.file.fileSize+"\r\n\r\n";
hsis.setData(sheader, sheader.length);
/* 4 */
var endsis = Components.classes[STRINGIS].createInstance(nsIStringInputStream);
var bs = new String("\r\n--" + BOUNDARY + "--\r\n");
endsis.setData(bs, bs.length);
/* 5 */
mis.appendStream(hsis);
mis.appendStream(buf);
mis.appendStream(endsis);
/* 6 */
var xmlr = new XMLHttpRequest();
xmlr.open("POST", "http://...", false); //À faire : remplacer par l'URL correcte
xmlr.setRequestHeader("Content-Length", mis.available());
xmlr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
/* 7 */
// ^_^
/* 8 */
xmlr.send(mis);
En théorie (et en pratique chez moi), cela devrait fonctionner et le fichier devrait être envoyé. Il ne reste plus qu'à recupérer le contenu dans le script appelé. En PHP, le tableau $_POST contiendra « addfile=1 » et le tableau $_FILES les informations sur le fichier que nous avons envoyé.
Avec « XMLHttpRequest », nous avons envoyé des données. Encore faut-il maintenant les traiter coté serveur. Dans les exemples, on a envoyé nos données vers des scripts PHP. Nous allons continuer avec PHP.
La récupération des données dépend de la méthode employé, et du type de contenu indiqué.
content-type indiqué | Données accessibles dans |
multipart/form-data | $_POST et $_FILES |
application/x-www-form-urlencoded | $_POST |
Autre | $HTTP_RAW_POST_DATA |
Il faut savoir que « XMLHttpRequest » envoie toujours les données en UTF-8, quel que soit l'encodage de la page XUL affichée. Donc vous recevrez quoi qu'il arrive toujours des données en UTF-8 dans $_POST, $_FILES ou $HTTP_RAW_POST_DATA.
Il faut donc veiller, à faire les transformations nécessaires si vous voulez stocker les données reçues, en ISO-8859-1 par exemple. En PHP, vous pouvez utiliser la fonction utf8_decode.
Pour éviter ces transformations, une solution est de travailler partout en UTF-8 : dans les fichier XUL, Javascript, PHP et de stocker vos données en UTF-8. Il ne faut donc pas oublier de :
<?xml version="1.0" encoding="UTF-8" ?>
Une fois les données traités, il est bon de renvoyer une réponse à « XMLHttpRequest ». Le contenu va dépendre du format utilisé pour l'échange, de ce que vous voulez récupérer côté client, etc.
Dans tous les cas, il faut toujours indiquer le type du contenu que vous allez renvoyer. En PHP, on fait cela avec la fonction header. Pour du XML, on indiquera :
header('Content-type: text/xml');
« » et l'on recuperera la réponse dans la propriété responseXML de « XMLHttpRequest ».
Pour du texte, on indiquera
header('Content-type: text/plain');
et l'on recuperera la réponse dans la propriété responseText de « XMLHttpRequest ».
Avec le script PHP suivant.
Le serveur peut renvoyer un fichier XML comme celui-ci :
<?xml version="1.0" encoding="ISO-8859-1"?>
<fruits>
<pomme couleur="verte" />
<fraise couleur="rouge" />
</fruits>
Le script PHP sera alors (par exemple) :
header('Content-type: text/xml');
echo '<?xml version="1.0" encoding="ISO-8859-1"?>'
. '<fruits>'
. '<pomme couleur="verte" />'
. '<fraise couleur="rouge" />'
. '</fruits>';
Et on peut récupérer son contenu dans javascript avec :
var fruits = p.responseXML.documentElement;
var couleurPomme = fruits.getElementsByTagName('pomme')[0].getAttribute('couleur');
var couleurFraise = fruits.getElementsByTagName('fraise')[0].getAttribute('couleur');
Si vous devez utiliser XMLHttpRequest depuis une extension, ou si vous ne voulez pas que l'envoi et la reception de données ne bloque votre application, vous devez utiliser XMLHttpRequest en mode asynchrone. Dans ce mode, votre code n'attend pas après le send() et passe à la suite, vous recevez une réponse via une « fonction de rappel ».
req = new XMLHttpRequest();
req.open('GET', 'http://xulfr.org/', true);
req.onreadystatechange = function ()
{
if (req.readyState == 4)
{
if(req.status == 200)
dump(req.responseText);
else
dump("Error loading page\n");
}
};
req.send(null);
À faire.
Pour échapper les caractères des paramètres, il est recommandé d'utiliser la fonction encodeURI() plutôt que escape().
Il peut être intéressant de fournir le bon Content-Type au serveur lors du téléversement :
...
sheader += "Content-Type: " + Components.classes["@mozilla.org/mime;1"]
.getService(Components.interfaces.nsIMIMEService)
.getTypeFromFile(fic) + "\r\n\r\n";
...
Si l'entête contient des cacactères non-ascii, il est possible de l'encoder en UTF-8 en intercalant un nsIScriptableUnicodeConverter dans le flux. Voir http://developer.taboca.com/cases/en/XML(..) pour plus de détails.
Copyright © 2003-2013 association xulfr, 2013-2016 Laurent Jouanneau - Informations légales.
Mozilla® est une marque déposée de la fondation Mozilla.
Mozilla.org™, Firefox™, Thunderbird™, Mozilla Suite™ et XUL™
sont des marques de la fondation Mozilla.