IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

AJAX Discussion :

[AJAX] xhr : envoi et retour d'un fichier


Sujet :

AJAX

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    155
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 155
    Points : 75
    Points
    75
    Par défaut [AJAX] xhr : envoi et retour d'un fichier
    Bonjour

    Je ne parviens pas à mettre en place une requête un peu particulière dont le schéma est le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    -->   files + paramètres
    <--  filescontent + paramètres
    L'utilisateur upload des fichiers avec quelques options, le serveur converti les fichiers et renvoie le résultat de la conversion avec quelques paramètres de retour.

    Comme il peut s'agir de gros fichiers le but est de déléguer le maximum de boulot au client (y compris le parsing).

    - 1ère question : en suivant cette logique y a t-il moyen de renvoyer un objet files au client, de la même façon qu'un objet files est envoyé au serveur, ceci afin de déléguer la lecture du fichier renvoyé au client ?

    - 2èm question : actuellement ce n'est pas le cas, le fichier converti est lu en php avec file_get_contents et renvoyé en texte, le problème est que j'ai une erreur js sur JSON.parse(xhr.responseText) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
    Le xhr.responseText ressemble à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [[0,[],"{ \"rootnode\": { \"name\": \"cube.obj ....
    Il est de la forme [ [ integer, [ strings ], string ] .. ] ou la dernière string est le filecontent

    Voici le code
    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    var formData = new FormData();
    var cnt = 0;
    for ( ext in toload )
    {
    	var arr = toload[ext];
    	for(var i= 0; i < arr.length; i++)
    	{
    		var file = arr[i];
    		formData.append('files[]', file, file.name);
    		cnt++;
    	}
    }
    formData.append('count', cnt);
    ... // + quelques autres paramètres ajoutés à la formData
     
    var xhr = new XMLHttpRequest();
    xhr.open('POST', 'modules/Import.php', true);
    xhr.addEventListener('load', function()
    {
    	document.body.innerHTML = xhr.responseText; // < Erreur ici
    	...
    }
    xhr.send(formData);
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    if ( $outcod == 0 )
    {
    	$content = file_get_contents( $dest ); // $dest est le fichier converti à renvoyer
    	$content = str_replace( array("\r", "\n", "\t"), '', $content );
    	if ( strlen($content) > 0 )
    		return [ $outcod, $out, $content ];
    	else
    		return [ $outcod, $out, $file ];
    }
    else
    	return [ $outcod, $out, $file ];
    }

    Quel est le problème de JSON.parse(xhr.responseText) ?
    Comment feriez vous ça sachant qu'encore une fois il peut y avoir des gros fichiers dont la lecture/parsing devrait à mon avis être fait le plus possible coté client ?

    En vous remerciant par avance.

  2. #2
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Hello,

    Citation Envoyé par krunch Voir le message
    - 1ère question : en suivant cette logique y a t-il moyen de renvoyer un objet files au client, de la même façon qu'un objet files est envoyé au serveur, ceci afin de déléguer la lecture du fichier renvoyé au client ?
    Rien de bien réaliste, non.

    Citation Envoyé par krunch Voir le message
    Quel est le problème de JSON.parse(xhr.responseText) ?
    Eh bien, corrige-moi si je me trompe, mais tes fichiers sont sans doute libres de contenir ce qu'ils veulent. Par exemple si l'idée leur prend de contenir l'octet 0x22 ça devrait pas être interdit, j'ai bon ?

    Or je constate que tes fichiers sont retransmis en JSON sous forme de string. Or une string JSON on sait que ça commence quand on trouve un " et on sait que ça finit quand on trouve l'autre ". Or l'octet 0x22 dans un fichier, ça ressemble diablement à un " quand on écrit le fichier comme si c'était une string.
    Résultat des courses le parseur voit que la string s'arrête en plein milieu du fichier, et que la suite du fichier c'est la suite du JSON, qui du coup est complètement invalide.


    Citation Envoyé par krunch Voir le message
    Comment feriez vous ça sachant qu'encore une fois il peut y avoir des gros fichiers dont la lecture/parsing devrait à mon avis être fait le plus possible coté client ?
    Je les renverrais sous forme d'URLs plutôt que directement dans le JSON. Puis il n'y a plus qu'à faire une requête pour chaque.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    155
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 155
    Points : 75
    Points
    75
    Par défaut
    Résultat des courses le parseur voit que la string s'arrête en plein milieu du fichier, et que la suite du fichier c'est la suite du JSON, qui du coup est complètement invalide.
    C'est bien possible, je ferai un essai avec d'autres fichiers, mais là il me dit "unexpected character at line 1 column 1" et le 1er caractère est un '['...

    Je les renverrais sous forme d'URLs plutôt que directement dans le JSON. Puis il n'y a plus qu'à faire une requête pour chaque.
    Alors j'envoie un ou plusieurs fichiers en objets files puis je fais autant de requêtes que de fichiers convertis pour les récupérer ?

    C'est juste un peu dommage de ne pas profiter du retour de la requête upload non ?
    Ça peut considérablement allonger le temps de latence, c'est la technique habituelle pour ce genre de chose ?

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par krunch Voir le message
    C'est bien possible, je ferai un essai avec d'autres fichiers, mais là il me dit "unexpected character at line 1 column 1" et le 1er caractère est un '['...
    Ah oui effectivement, bonne remarque. Non là le seul problème c'est qu'un objet JSON c'est pas un tableau, c'est un objet. Ça commence par { et pas [
    Après, rien ne t'empêche de bidouiller genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    {
      "response": [[0,[],"{ \"rootnode\": { \"name\": \"cube.obj ....
    }
    Bon ma remarque à propos des fichiers qui sont libres de contenir des séparateurs JSON tient, mais là le problème remonté c'était pas ça. Au passage je vois que ça te dérange pas d'en enlever tout ce qui est \r \n \t, à mon avis ça va plus marcher des masses après, mais bon.

    Citation Envoyé par krunch Voir le message
    C'est juste un peu dommage de ne pas profiter du retour de la requête upload non ?
    Un peu, mais enfin d'habitude c'est pas grand-chose face à la charge utile.

    Citation Envoyé par krunch Voir le message
    Ça peut considérablement allonger le temps de latence, c'est la technique habituelle pour ce genre de chose ?
    Alors oui c'est la technique habituelle, mais attention : on voit vraiment de tout dans la nature, concernant ce truc-là.

    Parce que effectivement, lorsque ça pose un problème question latence, eh bien il y a les solutions moins sympa.

    D'abord la plus simple, qui envoie la réponse en une fois mais en multipliant la taille du fichier par 4/3 : l'encoder en base64 et le mettre comme une string. Par contre il faut que le serveur encode et que le client décode. Surtout que derrière je suis pas sûr de ce que tu en fais, du fichier une fois que tu l'as récupéré en mémoire JavaScript.

    Sinon celle utilisée à l'upload, mais qui est compliquée côté download : faire une réponse en multipart/mixed qui contient le JSON dans une part et chaque fichier dans sa propre part.
    Problème : tu dois te taper la création du multipart en PHP toi-même, et le parsing du multipart en JavaScript toi-même, parce que j'ai pas connaissance de bibliothèque qui le fasse pour toi. Et il reste que les fichiers, une fois extraits, on se demande ce que tu vas en faire.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    155
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 155
    Points : 75
    Points
    75
    Par défaut
    Alors il se trouve qu'en fait j'ai fait n'importe quoi, car l'erreur venait en fait d'un var_dump que j'avais oublié de désactiver, grosse andouille que je suis
    En plus de ça j'ai oublié de mentionner le echo json_encode($back); de fin du php

    Toutefois par rapport à ce que tu dis sur JSON.parse() la réponse de la requête d'upload est bien la suivante et JSON.parse() marche aussi avec les tableaux (du moins dans FF), d'ailleurs si je tape JSON.parse('[1, 2]'); dans la console j'obtiens un tableau et pas d'erreur.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [[0,[],"{ \"rootnode\": { \"name\": \"cube.obj ....
    Finalement mon truc marche avec exactement le code de mon message initial (j'ai juste enlevé un var_dump quelque part ailleurs), mais je ne sais pas encore si ça marche partout.


    Par rapport à la structure il semble ta solution (renvoyer des urls et refaire des requêtes) est sans doute plus propre en quelque sortes.
    Le but était juste de minimiser les requêtes, c''est pourquoi ça me paraissait une solution optimale de tout renvoyer dans le retour, mais en fait je sais pas trop...

    La vérité c'est que côté serveur je suis une bille, alors comme tu as l'air d'avancer d'autres solutions inconnues pour moi je te fais le topo rapido.
    Il s'agit de fichiers 3D, je bosse sur une interface basée sur three.js. Le principe c'est qu'on charge un fichier à un format d'échange disons 'standard' comme le .OBJ .STL ou un codage en .JS. Seulement en face, dans le vrai monde, il y a une ribambelle de formats possibles pour la 3D, et les formats standards ont l'inconvénient de ne pas forcément être disponible dans ton logiciel (File/Export), ou d'être très imparfaits (beaucoup de perte au niveau des matériaux par exemple, si ils sont exportés..). Heureusement il existe aussi une ribambelle de bibliothèques/scripts open source qui font des conversions. Certaines sont assez abouties, et s'attaquent même à des formats propriétaires bien opaques comme par exemple le .DWG. Il y en a de toutes sortes et il s'agit généralement de .EXE, .JAR, .PY, java ... côté serveur donc.
    Bref j'ai fait une interface pour ça et c'est ce processus complet (jusqu'au chargement) qui fonctionne, du moins chez moi car je sais bien que l'hébergement serait une autre histoire (serveur dédié juste à cause de ce module de conversion a priori).

    Concernant les fichiers à renvoyer il peut s'agir de simples textes, de binaires, de compilés (.CTM), et en plus de ça j'essaierai bien la compression gzip...
    Voilà le cahier des charges... J'avais aussi commencé à regarder du côté des web service et notamment soap mais on m'a dit que c'était pas terrible. Donc je suis preneur de tout conseil pour ça. Si par exemple tu me dis que la technique habituelle est de refaire des requêtes derrière et que ma technique est mauvaise je te crois, parce que j'en sais rien en fait...

    ---
    Ah oui d'ailleurs, que veut dire ?
    Un peu, mais enfin d'habitude c'est pas grand-chose face à la charge utile.

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par krunch Voir le message
    Finalement mon truc marche avec exactement le code de mon message initial (j'ai juste enlevé un var_dump quelque part ailleurs), mais je ne sais pas encore si ça marche partout.
    Ça ne devrait pas marcher partout, pour les raisons déjà mentionnées.

    Citation Envoyé par krunch Voir le message
    Bref j'ai fait une interface pour ça et c'est ce processus complet (jusqu'au chargement) qui fonctionne, du moins chez moi car je sais bien que l'hébergement serait une autre histoire (serveur dédié juste à cause de ce module de conversion a priori).
    Même avec du dédié il va falloir s'assurer que c'est du Windows. Sur le principe je vois pas pourquoi ce serait un problème, mais j'ai jamais eu ce besoin-là -_-°.
    À moins que ces .exe ne passent bien sur wine...

    Citation Envoyé par krunch Voir le message
    Voilà le cahier des charges...
    Je me pose quand même un peu la question de la persistance de la chose. Les trucs dessinés un peu comme three.js, il seront pas sauvegardables ? S'ils le sont, j'imagine que ce sera côté serveur, et donc que le serveur doit retenir, et renvoyer à chaque visite, toutes les ressources 3D.
    Dans ce cas-là, franchement, quelle différence si l'opération de conversion renvoie les fichiers en une fois... À la prochaine visite il faudra les recharger de toute manière.

    Citation Envoyé par krunch Voir le message
    J'avais aussi commencé à regarder du côté des web service
    Ton bidule de conversion est déjà pas loin d'être un webservice... Qui offre une seule ressource mais bon.

    Citation Envoyé par krunch Voir le message
    et notamment soap mais on m'a dit que c'était pas terrible.
    Je trouve aussi.

    Citation Envoyé par krunch Voir le message
    Si par exemple tu me dis que la technique habituelle est de refaire des requêtes derrière et que ma technique est mauvaise je te crois, parce que j'en sais rien en fait...
    Mauvaise, mauvaise, ça dépend du point de vue.

    En l'état tu as des risques que ça foire dans certains cas, parce que mettre du binaire dans une string c'est une idée foireuse.
    Si tu l'encodais en base64 par exemple, ce problème disparaîtrait, mais ça multiplie la taille du fichier par 4/3 (et puis ça commence à faire de la jolie string deux fois entièrement en mémoire aussi, mais bon de nos jours, pourquoi pas.)
    Pour éviter ça, d'habitude, on fait une requête pour la conversion et une requête pour chaque fichier. Mais, c'est vrai, cette attente entre chaque requête peut créer de la latence.
    Donc grosso-merdo, je dis que ta technique elle tient debout, elle a un problème qu'il faut adapter, mais dans l'idée ça se tient.

    Bien sûr il existe d'autres solutions mais on s'éloigne des sentiers battus.

    Citation Envoyé par krunch Voir le message
    Ah oui d'ailleurs, que veut dire ? [Un peu, mais enfin d'habitude c'est pas grand-chose face à la charge utile.]
    Ben c'est vrai que faire plusieurs requêtes au lieu d'une, ça fait un overhead pour chaque nouvelle requête, de même que l'attente synchrone de communication pour lancer la requête suivante.
    Mais il ne faut pas oublier qu'on parle d'échanger des fichiers après une conversion, là, c'est du traitement lourd et beaucoup de données. L'overhead d'une requête par fichier devrait logiquement être imperceptible. Après si les fichiers font genre 3 ou 4 ko c'est une autre histoire.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    155
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 155
    Points : 75
    Points
    75
    Par défaut
    Même avec du dédié il va falloir s'assurer que c'est du Windows. Sur le principe je vois pas pourquoi ce serait un problème...
    Oui ou recompiler etc.. il y a tout ça et le fait que configurer un serveur n'a pas l'air simple quand on l'a jamais fait, mais le problème serait surtout financier en fait ... (là dessus j'avais fait une autre question, je pense faire de mon poste un serveur dans un premier temps).

    Les trucs dessinés un peu comme three.js, il seront pas sauvegardables ?
    Dans mon idée uniquement si tu le souhaites. D'autre part tu peux éditer des trucs dans l'interface, donc ils seront sauvegardés dans un format standard (.js) par une requête finale si tu le demandes.
    Du coup la phase de chargement est séparée, d'ailleurs si il n'y a pas de conversion le fichier (que j'appelle 'standard' : .obj .js) est simplement lu en local. Et si il y a conversion le serveur efface les fichiers (uploadés et convertis) après le renvoi.

    Pour ça avec ma méthode j'efface juste les fichiers après renvoi donc ... Avec celle des urls il faut détecter la fin de session (ou quelquechose comme ça) ?

    Dans ce cas-là, franchement, quelle différence si l'opération de conversion renvoie les fichiers en une fois... À la prochaine visite il faudra les recharger de toute manière.
    Pour la prochaine visite tu auras donc sauvegardé toute la scène dans 1 seul fichier serveur.
    Sinon pour la conversion la question reste valable ... Il me semble qu'elle ne concerne plus que le temps de latence, et face aux inconvénients dont tu parles je préfère de plus en plus ta méthode habituelle.

    Ben c'est vrai que faire plusieurs requêtes au lieu d'une, ça fait un overhead pour chaque nouvelle requête, de même que l'attente synchrone de communication pour lancer la requête suivante.
    Je pensais plus à l'attente synchrone, la latence internet quoi, mais il est vrai qu'on fera peu de conversions de fichiers depuis son mobile ou, hélas, d'un village isolé du fond de l'Afrique... J'ai du un peu délirer là dessus (entre les règles d'optimisation et la réalité on sait jamais trop).

    Bref cette méthode a l'air effectivement trop risquée face à la diversité des trucs à renvoyer, peut être aussi pour la gestion des erreurs.

    Juste si tu sais comment on détecte / déclenche une fin de session pour l'effacement des fichiers ?


    Pour ce qui est des webservices j'en sais très peu là dessus (en gros que c'est une autre structuration des requêtes, et que ça a l'air cool), mais si ça n'apporte pas grand chose pour ce projet (ce que tu as l'air de dire) je préfère les oublier ...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [AJAX] Requete Cross-Domain: retour xhr à 0
    Par xxkirastarothxx dans le forum AJAX
    Réponses: 0
    Dernier message: 26/06/2013, 17h17
  2. Réponses: 7
    Dernier message: 10/09/2009, 15h00
  3. [Socket][Byte] Probleme d'envoi d'une taille de fichier
    Par Erok dans le forum Entrée/Sortie
    Réponses: 14
    Dernier message: 12/05/2009, 17h38
  4. Envoi d'un mail avec fichier en pièce jointe
    Par cjacquel dans le forum MFC
    Réponses: 1
    Dernier message: 14/06/2005, 16h30
  5. envoi mail avec piece jointe fichier excel
    Par flogreg dans le forum ASP
    Réponses: 12
    Dernier message: 20/12/2004, 16h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo