2010-07-28 4 views
11

Salutations,Déclencher un téléchargement de fichier sans demande de serveur

je travaille sur une application JS qui fait un travail complexe et enregistre des informations (en fait, jusqu'à des centaines de lignes) sur une <div>.

Mon but est d'avoir un bouton "Enregistrer le journal" qui déclenche la boîte de dialogue de téléchargement du navigateur pour enregistrer le contenu de ma connexion <div>.

Plus de façon concise, ce sont les conditions requises pour cette fonction:

  • L'utilisateur final doit avoir un contrôle total sur le fichier. Il/elle devrait être en mesure de sauvegarder/archiver pour référence future, l'envoyer au service d'assistance pour obtenir de l'aide pour résoudre un problème, le recharger dans l'application, etc. L'API de stockage Web de HTML5 n'aide pas ici être enregistré dans un emplacement défini par le navigateur et ne serait pas facilement récupérable sauf à partir du JS qui le crée).
  • L'application doit pouvoir fonctionner hors ligne (au moins dans certaines circonstances). Cela, et l'efficacité, c'est pourquoi j'ai rejeté l'idée de POSTing les données sur le serveur pour le récupérer avec un en-tête "Content-disposition".
  • Le fichier doit être correctement marqué comme text/plain, afin que le navigateur puisse suggérer des actions par défaut (comme "Ouvrir sur le bloc-notes") comme avec un téléchargement de fichier normal. Cela peut être considéré comme un aspect spécifique de la première exigence. Dire à l'utilisateur de copier-coller le contenu du <div> dans un éditeur de texte et l'enregistrer à partir de là est vraiment horrible, et c'est exactement pourquoi je tente d'éviter.

J'ai recherché sur ce site, sur les sites WHATWG et W3C et sur le web en général sans succès. Est-ce faisable du tout?

Le plus proche que j'ai obtenu est en utilisant un data: url. Ma première tentative, en exécutant une action POST, n'a pas réussi à obtenir un type de contenu, ce qui aurait pour effet de revenir à l'heuristique de l'agent UA. Je l'ai un peu mieux en appelant un lien <a> pour ressembler à un bouton et en lui donnant un attribut type, mais alors l'UA jouera trop mal et rendra le contenu au lieu de sauvegarder (et demande à l'utilisateur de sauvegarder le fichier depuis le navigateur à cette étape devient encore pire que l'approche copier-coller, puisque la sauvegarde de la page varie énormément d'un navigateur à l'autre).

S'il y avait juste un moyen de combiner un data: url avec une allusion de type «content-disposition», les choses pourraient aller très bien.

Cordialement, Herenvardo

+1

L'utilisation d'un plugin comme Flash est-elle hors de question? Je ne sais pas s'il est possible de faire avec le HTML standard, mais ce serait assez facile si Flash était une option ... –

+0

J'ai eu une question similaire http://stackoverflow.com/questions/2832392/can-you- do-file-io-using-javascript-without-activex mais seulement une réponse. Je ne pense pas que ce soit possible cependant. –

+0

Est-ce que le "copier dans le presse-papiers avec du code et dire à l'utilisateur de le coller dans le bloc-notes (ou éditeur de texte favori)" idée venir? Le presse-papiers peut gérer des mégaoctets, mais le bloc-notes pourrait s'étouffer avec quelques mégaoctets. D'autre part: voir http://stackoverflow.com/questions/17836273/export-javascript-data-to-csv-file-without-server-interaction – TWiStErRob

Répondre

2

Malheureusement, ce n'est pas quelque chose que vous pouvez faire avec des fonctionnalités de navigateur normales. Quelque chose comme flash ou un plugin spécifique au navigateur vous obtiendra ce dont vous avez besoin, mais les limites de sécurité dans javascript ne vous permettra pas de télécharger des données arbitraires créées dans le navigateur. De plus, l'URL 'data' n'est pas supportée par toutes les combinaisons navigateur/version. Je ne sais pas si vos utilisateurs sont limités par le navigateur qu'ils utilisent ou non, mais cela peut limiter ce que vous pouvez faire avec cette solution.

+0

Merci! Il semble que l'approche basée sur le plug-in (ou Flash) soit la seule façon de répondre à toutes les exigences. D'un autre côté, le support de 'data:' n'est pas vraiment un problème: l'application dans son ensemble repose sur beaucoup de fonctionnalités HTML5, donc il y a déjà beaucoup de navigateur, nécessitant un support pour 'data:' won ' t être ce gros problème. –

+1

En outre, Silverlight peut être une option viable ici. –

2

Cette solution est légèrement compliquée mais fonctionnerait pour vos besoins, c'est peut-être une option.

Créez un serveur Web personnalisé qui renvoie simplement le contenu de tout GET ou POST en tant que texte/brut.

Hébergez ce serveur Web sur la même case que l'application Web, mais sur un autre port. Lorsque vous cliquez sur le bouton Enregistrer le journal, la demande est envoyée au serveur personnalisé et le fichier texte est renvoyé.

est ici une preuve de serveur concept en Java qui fera juste que:

// After running this program, access with your browser at 127.0.0.1:8080 

import java.net.*; 
import java.io.*; 

public class ReturnTextFile 
{ 

    public static void main(String[] args) 
    { 

    try 
    { 
     ServerSocket server = new ServerSocket(8080); 
     Socket connection = null; 

     while (true) 
     { 

     try 
     { 
      connection = server.accept(); 

      BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); 

      String input = in.readLine(); 

      // TODO: Clean up input 

      Writer out = new OutputStreamWriter(connection.getOutputStream()); 

      String output = "HTTP/1.1 200 OK\n" + 
        "Connection: close\n" + 
        "Content-Disposition: attachment; filename=log.txt\n" + 
        "Content-Type: text/plain; charset=utf-8\n" + 
        "\n"; 

      output += input; 

      out.write(output); 

      out.flush(); 

      connection.close(); 
     } 
     catch (IOException ex) 
     { 
      ex.printStackTrace(); 
     } 
     finally 
     { 
      if (connection != null) 
      { 
      connection.close(); 
      } 
     } 

     } 

    } 
    catch (IOException ex) 
    { 
     ex.printStackTrace(); 
    } 

    } 
} 
+0

+1 pour une approche aussi intéressante. Je vais certainement garder à l'esprit l'idée d'un serveur local pour de futurs projets, mais la réponse de Mike semble résoudre le problème beaucoup plus facilement. –

2

Vous pouvez définir le type de contenu dans l'URL data:, quelque chose comme ceci:

data:text/plain,this is some text 

Cependant, cela a toujours le problème du navigateur le rendant automatiquement en texte. Vous avez vraiment deux options que je peux voir. Le premier est que vous définissez le type sur un type de type binaire afin que le navigateur n'essaie pas de le rendre, ou que vous ayez le type text/plain et que l'utilisateur clique avec le bouton droit et enregistre en tant que. Peut-être que quelque chose here peut aider?

1

Je suis allé sur cette route, et je voulais aussi le faire purement côté client. Mais c'est impossible. La seule façon de déclencher la boîte de dialogue de sauvegarde sans aucun problème consiste à effectuer une requête HTTP POST et à demander au serveur de répondre avec un en-tête content-disposition. J'ai la fonctionnalité souhaitée dans les extraits de code sur my dusty old blog. J'ai un formulaire avec un champ caché pointé vers un gestionnaire HTTP personnalisé. Javascript saisit le texte interne du bloc de code, le place dans le champ caché et soumet le formulaire. Le serveur répond avec le corps entier de la demande, avec les en-têtes requis. Pas d'actualisation, vous cliquez dessus et vous obtenez une boîte de dialogue de sauvegarde. Fonctionne très bien!

+0

Qu'en est-il de l'utilisation d'un en-tête 'http-equiv' en jonction avec un URI' data: 'pour simuler l'en-tête? Cela fonctionnerait-il? – haxxerz

Questions connexes