Apache Adobe Flex TutorialTutoriaux Adobe Flex & AIR en Français

24juin/0812

Flex HTTPService – Envoyer des requêtes et traiter le résultat (exemple)

HTTPService est un composant qui vous permet de faire des requêtes vers de simples services HTTP, tels que des fichiers texte, des fichiers XML ou des scripts/pages qui retournent de la donnée en dynamique. Vous devez toujours définir une valeur pour la propriété "url" d'un objet HTTPService. La propriété "url" dit à l'objet où il peut trouver la ressource vers laquelle il va faire la requête. La valeur peut aussi bien être une URL relative qu'une URL absolue. Le code suivant utilise du MXML pour créer un objet HTTPService qui charge du texte depuis un fichier .txt appelé data.txt, sauvegardé dans le même dossier que le fichier SWF compilé:

<mx:HTTPService id="textService" url="data.txt"/>

Maintenant que vous savez comment créer une nouvelle instance de HTTPService, nous allons voir comment envoyer des requêtes et en récupérer la réponse.

Envoyer des requêtes avec <mx:HTTPService>

Créer un objet HTTPService ne fait pas automatiquement la requête pour charger la donnée. Pour faire cette requête, vous devez appeler la méthode send(). Vous pouvez appeler la méthode send() en réponse à n'importe quel événement du Framework ou de l'utilisateur. Par exemple, si vous voulez faire une requête aussi tôt que l'application s'initialise, vous pouvez appeler send() en réponse à l'événement "initialize". Si vous voulez charger la data quand l'utilisateur clique sur un bouton, vous pouvez appeler la méthode send() en réponse à l'événement "click":

textService.send();

Récupérer la réponse de la requête HTTPService

La méthode send() fait la requête, mais la réponse peut ne pas être retournée instantanément. Au lieu de cela, l'application doit attendre l'événement qui se produira à l'arrivée du résultat. L'événement "result" se produit quand une réponse complète a été retournée. L'exemple suivant affiche une Alert lorsque la donnée est chargée:

<mx:HTTPService id="textService" url="data.txt" result="mx.controls.Alert.show('Données chargées')"/>

Bien sur, normalement, vous voudrez faire des choses plus utiles que d'afficher une Alert lorsque la data est chargée. De manière plus générale, vous voudrez afficher la donnée qui vient d'être chargée. Vous pouvez récupérer ces données (celles qui viennent d'être chargées) en utilisant la propriété "lastResult". Du texte est toujours chargé comme une String. Cependant, le composant HTTPService est capable de convertir automatiquement de la data serialisée dans des tableaux associatifs. C'est pourquoi la propriété lastResult est typée comme Object. Si vous voulez l'utiliser comme une String, vous devez faire un cast (conversion de type).

L'exemple suivant charge un fichier texte depuis un fichier et l'affiche dans un TextArea:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	initialize="initializeHandler(event)">
	<mx:Script>
		<![CDATA[
			private function initializeHandler(event:Event):void{
				textService.send();
			}

			private function resultHandler(event:Event):void{
				textArea.text = String(textService.lastResult);
			}
		]]>
	</mx:Script>

	<mx:HTTPService id="textService" url="data.txt" result="resultHandler(event)"/>

	<mx:TextArea id="textArea"/>
</mx:Application>

Bien que vous pouvez gérer l'événement result de manière explicite, il est bien plus commun d'utiliser le data binding. L'exemple suivant fait la même chose mais en utilisant le data binding:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	initialize="initializeHandler(event)">
	<mx:Script>
		<![CDATA[
			private function initializeHandler(event:Event):void{
				textService.send();
			}
		]]>
	</mx:Script>

	<mx:HTTPService id="textService" url="data.txt"/>

	<mx:TextArea id="textArea" text="{textService.lastResult}"/>
</mx:Application>

Lorsque c'est possible, HTTPService déserialise la donnée qu'il charge, un peu comme il interprèterai la donnée placée dans un tag <mx:Model>. Par exemple, on considère la donnée XML suivante:

<countries>
	<country>Sélectionner</country>
	<country>Canada</country>
	<country>USA</country>
</countries>

Si vous chargez cette data en utilisant HTTPService, elle sera parsée en un objet nommé "countries" qui contient un contient un tableau nommé "country", chaque élément correspondant à un élément <country>. L'exemple de code suivant montre comment charger une ComboBox avec de la donnée XML en live. Il utilise aussi le data binding pour peupler le dataprovider de la ComboBox:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	verticalAlign="middle" horizontalAlign="center"
	initialize="initializeHandler(event)">
	<mx:Script>
		<![CDATA[
			private function initializeHandler(event:Event):void{
				countryService.send();
			}
		]]>
	</mx:Script>

	<mx:HTTPService id="countryService" url="countries.xml"/>

	<mx:VBox>
		<mx:ComboBox id="country" dataProvider="{countryService.lastResult.countries.country}"/>
	</mx:VBox>
</mx:Application>

Flex Source Code Download: Télécharger le code source complet de l'application

This movie requires Flash Player 11

Comme on l'a déjà vu, les résultats des HTTPService sont interprétés comme du texte s'ils sont des blocs de texte, et si ces résultats sont sous forme XML, ils sont parsés en un Object. Cependant, c'est uniquement le comportement par défaut. Vous pouvez explicitement imposer le type en utilisant la propriété "resultFormat" de l'objet HTTPService. La valeur par défaut est "object", qui donne le comportement par défaut. Vous pouvez spécifier une des valeurs suivantes:

  • text: la données n'est pas parsée du tout mais traitée comme du texte brut
  • flashvars: la donnée doit être encodée comme une URL , et elle sera parsée en un objet avec les propriétés correspondant aux paires nom/valeur
  • array: la donnée doit être au format XML, et elle sera parsée en objets comme si on avait le paramètre par défaut. Cependant, dans ce cas, le résultat est toujours un Array. Si la donnée n'est pas automatiquement parsée dans un Array, la donnée parsée sera placée dans un Array
  • xml: la donnée doit être au format XML, et est interprétée comme du XML en utilisant la classe ActionScript XMLNode
  • e4x: la donnée doit être au format XML, et est interprétée comme du XML en utilisant la classe ActionScript 3.0 XML (E4X)

Articles similaires

Commentaires (12) Trackbacks (1)
  1. Bonjour,

    Je découvre Flex depuis quelques heures et je suis heureux d'être tombé sur votre blog : c'est clair, précis, efficace ! Bravo pour le travail et merci de le partager !
    J'ai une question concernant l'exemple que vous présentez : l'alimentation d'une combo à partir d'un fichier XML. La plupart du temps, le combo affiche des valeurs mais le code exploite une donné numérique non affichée (mais qui n'est pas l'index dans la liste des valeurs du combo). Si je prends le cas de votre combo des pays, j'aurais besoin d'afficher les pâys comme vous le faites, mais aussi de charger un code pays.
    Le fichier xml serait quelque chose comme ça :

    Canada1233
    USA6732

    Le combo devra afficher Canada et USA mais quand l'utilisateur choisit un pays, le programme devra exploiter le code 1233 ou 6732.
    Si vous avez deux minutes pour me dire comment faire, j'en serais ravi.
    Merci encore pour tout ce que vous faites. Et bonne année !
    PS : malheureusement, les balises XML ne sont pas affichées correctement par WordPress :-(

  2. Salut,
    alors pour que ta ComboBox affiche un label défini, il faut que tu utilises une labelFunction pour afficher un label personalisé (ici la concaténation de 2 valeurs présentes dans ton dataProvider et pour obtenir le code, tu peux simplement prendre le selectedItem de la comboBox comme ceci:
    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
    <mx:XML id="dp" xmlns="">
    <root>
    <pays label="Canada" code="1231"/>
    <pays label="France" code="1981"/>
    </root>
    </mx:XML>
    <mx:Script>
    <![CDATA[
    private function customLabelCode(item:Object):String{
    var strReturn:String = "";
    strReturn = item.@label + " " + item.@code;
    return strReturn;
    }
    private function getTheCode():void{
    var code:String = comboPays.selectedItem.@code;
    trace ("code sélectionné: "+code);
    theCode.text = "code pays: "+code;
    }
    ]]>
    </mx:Script>

    <mx:ComboBox id="comboPays" dataProvider="{dp.pays}" labelFunction="customLabelCode"/>
    <mx:Button label="Obtenir le code Pays" click="getTheCode()"/>
    <mx:Label id="theCode"/>
    </mx:Application>

  3. Très bonnes explications. Merci!

  4. Bonjour,

    Je cherche désespérement depuis plusieurs jours comment initialiser proprement une combobox sur une valeur particulière. J'ai compris qu'il n'y a pas d'autre solution que de le faire "à la main" en déterminant l'index de l'item à préselectionner, mais mon problème est au niveau de l'event que je dois utiliser. L'initialisation de la liste se fait correctement la première fois que la combobox est affichée (event = creationComplete), mais ensuite, je ne sais pas par quel event remettre à jour l'élément sélectionné. Le cas est le suivant :
    une ViewStack qui comprend 2 Panel : un pour afficher les informations d'un utilisateur, un second pour permettre de modifier les infos de ce même utilisateur. Un seul Panel est affiché à la fois. Il faut que j'initialise la combobox qui contient les "titres" (Mlle, Mme, Mr...). La 1ère fois que le Panel de modification est affiché c'est OK (event = creationComplete), mais si je retourne sur la synthèse puis à nouveau sur le Panel de modification, la combobox existe déjà et creationComplete n'est plus appelé, la combobox est donc positionnée par défaut sur le 1er élément... Quel event dois je utiliser pour ça?
    QQn à une idée pour m'aider?
    Merci!

    Sébastien

  5. Salut,
    Comme tu l'expliques, il faut remettre par défaut la valeur de ta combobox au moment du changement de panel du ViewStack.
    Tu as donc 2 solutions. Pour changer entre tes 2 Panel, tu dois bien utiliser un bouton ou quelque chose comme cela qui modifie le selectedIndex ou le selectedChild de ton ViewStack. Tu peux remettre ta ComboBox à jour à ce moment-là en appelant la fonction que tu appelles sur le creationComplete.
    Ou alors tu peux utiliser l'évènement "change" de ViewStack, et faire la même manipulation. Si tu ne veux pas réinitialiser ta comboBox à n'importe quel change (seulement pour le retour sur le Panel 1 par ex), tu peux faire des vérifications avec les propriétés oldIndex et newIndex qui sont propagées avec l'évènement change.

    Voila :)
    Fabien

  6. Merci Fnicollet!
    Effectivement, je me suis trop focalisé sur la combobox et je n'ai pas pensé à son conteneur. J'ai utilisé l'Event "show" du Panel qui contient la combo et ça fonctionne parfaitement!
    Merci de ta réponse aussi rapide.

    Sébastien

  7. Bonjour,
    Merci pour votre tutoriel et votre super site.
    J'utilise HTTPService pour récupérer les URL écrits en dur dans un fichier XML sous format e4x. Ces URL sont les adresses de fichiers mp3 que l'application AIR va lire pour diffuser les musiques.
    Mon problème c'est que ces données récupérées par le HTTPService
    (ex: http://monsite.com/xxxx.mp3) sont écrits dans le répertoire Temporary Internet Files de IE...
    alors que justement ce sont les données que je voudrais cacher...
    Y aurait-il une méthode ou une propriété que le composant HTTPService possède pour empêcher cela ?

    Je vous remercie beaucoup.

  8. Bonjour,
    je ne connaissais pas que HTTPService sous Air écrivait des fichiers dans les Temporary Files de IE mais admettons (ce n'est pas du à une lecture dans un composant mx:HTML par hasard ?). Sinon, pour masquer ces informations, tu peux encoder/décoder ton XML en Base64. Il sera ainsi illisible par un simple éditeur de texte (mais toujours décodable). Pour l'encodage en Base64 en AS3, voici une ressource intéressante(il en existe d'autres)
    http://dynamicflash.com/2006/09/actionscript-30-base64-encoderdecoder/

    Fabien

  9. Merci beaucoup de m'avoir répondu et si...vite.
    A mon humble connaissance , je crois que ce n'est pas HTTPService qui écrit dans les Temporary mais ce sont les composants de flex.medias.SoundChannel ( load(),play()...) mais comme je suis en train de chercher comment faire, alors je prospecte tant que je peux.
    De toute façon, je vous remercie pour l'encodage du XML en Base64. Je ne savais pas que cette méthode existe.
    Peut-être cela pourrait-il aider quelqu'un mais combiner avec une fausse extension des fichiers mp3 (par ex, metrre comme extension .bmp les fichiers mp3, le play() d'un sound() s'effectue sans problème) et un XML encodé en Base64, ces 2 méthodes seront déjà une petite arme contre les téléchargements de vos créations musicales... Pas incontournables et pas infaillibles mais déjà elles [ces méthodes] donneront un peu de mal à découvrir entièrement les fichiers exposés.
    J'y vais de ce pas m'y mettre sur l'encodage du XML
    Encore merci beaucoup

    Rhoby

  10. Bonjour,
    Dans un premier temps merci pour ce site.
    Ensuite dans un projet Flex j'utilise les httpservice pour "communiquer" avec un server IIS (asp)
    tout fonctionne bien, je déclare l'url de mon httpservice de cette façon

    Actionscript:
    1. var _strDomain = "http://localhost/site";
    2. http.url = _strDomain + "/page.asp";

    Au moment de déployer je modifie juste mon strDomain de cette façon par exemple

    Actionscript:
    1. var _strDomain = "http://www.monsite.fr/site";

    Mon server IIS de dev et celui de prod étant légèrement différent je doit switcher régulièrement pour tester mon code. De plus j'utilise des popups (composants Flex) dans lesquels je doit redéclarer mon _strDomain.
    Cela devient onc vite laborieux.
    Existe-t-il une solution plus simple ( moins laborieuse) ?

    Désolé si ce n'est pas le bon endroit pour poster cela.

    a++

    Nico

  11. Vu qu'il n'y pas (encore?) de forum sur ce blog, il n'y a pas vraiment de mauvais endroit, pas de souci.
    Pour ton problème de String accessible de partout et facilement modifiable, tu as plusieurs solutions, plus ou moins adaptées selon tes contraintes.
    En voici quelques unes auxquelles je pense (il y en a surement d'autres):
    - Passer l'url de ton service (enfin le domain) dans des flashVars, dans le code HTML qui te sert à intégrer le fichier SWF dans la page HTML (plus d'infos sur google ou ici http://livedocs.adobe.com/flex/3/html/help.html?content=passingarguments_3.html)
    - Mettre l'url dans un fichier JavaScript que tu inclus dans ta page. Tu fais ensuite une mini fonction JavaScript qui retourne ton domain. Il te suffit ensuite d'appeler cette méthode avec ExternalInterface dès que tu en as besoin dans toute ton appli (sans oublier de modifier le fichier HTML pour y mettre la balise script pour inclure le petit fichier JS).
    - Mettre l'url dans un fichier externe que tu peux charger au démarrage de ton application. Tu stockes ensuite ca dans une classe genre Singleton accessible de partout pour pouvoir y accéder dans ton application.

    Voila, il y en a d'autres encore plus tordue je pense mais l'une de celles-ci devraient aller :)

    Fabien

  12. Merci pour ta réponse super rapide et encore bravo pour cette mine d'informations..

    ++
    Nico


Leave a comment

(required)