2010-07-28 51 views
11

问候,触发文件下载,没有任何服务器要求

我工作的一个基于JS的应用程序,做了一些复杂的工作,并记录在<div>的一些信息(实际上,多达数百行)。

我的目标是有一个“保存日志”按钮,触发浏览器的下载对话框来保存我的日志记录<div>的内容。

更简洁,这是此功能的要求:

  • 最终用户必须对文件的完全控制。他/她应该能够保存/存档以供将来参考,将其邮寄给支持部门以获得帮助以解决某些问题,将其重新加载到应用程序中等。因此,HTML5的Web Storage API在这里没有帮助(数据会保存到浏览器定义的位置,除了创建它的JS之外,不会轻易检索到)。
  • 应用程序必须能够脱机工作(至少在某些情况下)。这和效率是我放弃将数据发布到服务器以通过“Content-disposition”标题取回数据的原因。
  • 该文件应该被正确标记为text/plain,因此浏览器可以像使用普通文件下载一样建议默认操作(如“在记事本中打开”)。这可以被看作是第一个要求的一个特定方面。
  • 告诉用户将<div>的内容复制粘贴到一个文本编辑器中并从那里保存是绝对可怕的,正是我试图避免的原因。

我一直在搜索这个网站,在WHATWG和W3C的网站和一般的网络上没有成功。这是可行的吗?

我得到的距离最近的是使用data:网址。我第一次尝试执行POST操作时,无法获得内容类型,因此它会回退到UA的启发式。通过将<a>链接样式化为看起来像一个按钮并给它一个type属性,我得到了稍微好一点,但是然后UA将太智能并且呈现内容而不是保存(并且要求用户将文件从浏览器保存到该步骤比采用复制粘贴方法变得更糟,因为页面保存在浏览器之间变化很大)。

如果只有某种方式可以将data: url与“内容处置”类似的提示结合起来,那么事情可能会非常顺利。

问候, Herenvardo

+1

正在使用Flash之类的插件吗?我不知道是否可以使用标准的HTML,但如果Flash是一个选项,它会很容易... – 2010-07-28 23:02:51

+0

我有一个类似的问题http://stackoverflow.com/questions/2832392/can-you- do-file-io-using-javascript-without-activex但只有一个答案。但我认为这是不可能的。 – 2010-07-28 23:26:50

+0

“用代码复制到剪贴板并告诉用户将它粘贴到记事本(或最喜欢的文本编辑器)”的想法出现了吗?剪贴板可以处理兆字节,但记事本可能会在几兆字节上窒息。另一方面:请参阅http://stackoverflow.com/questions/17836273/export-javascript-data-to-csv-file-without-server-interaction – TWiStErRob 2014-02-18 09:35:29

回答

2

很不幸,这是不是你可以用普通的浏览器功能做。像flash或特定于浏览器的插件将为您提供所需的内容,但JavaScript内的安全性限制不会让您下载在浏览器内创建的任意数据。

此外,所有浏览器/版本组合都不支持“数据”网址。我不确定您的用户是否受限于他们正在使用的浏览器,但这可能会限制您可以使用该解决方案执行的操作。

+0

谢谢!看来基于插件(或Flash)的方法是满足所有要求的唯一方式。另一方面,对'data:'的支持并不是什么大问题:整个应用程序依赖于很多HTML5功能,因此已经有一个沉重的浏览器需求,需要支持'data:'赢得'这很大程度上是一个问题。 – 2010-07-30 18:08:02

+1

另外,Silverlight在这里可能是一个可行的选择。 – 2010-07-30 18:27:26

2

该解决方案稍微复杂,但可以满足您的需求,也许这是一种选择。

创建一个自定义Web服务器,它只是以文本/纯文本形式返回任何GET或POST的内容。

将Web服务器托管在与Web应用程序相同的盒子上,但运行在不同的端口上。当您单击保存日志按钮时,请求将被发送到自定义服务器并返回文本文件。

以下是一个Java概念服务器的证明,将做到这一点:

// 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这样一个有趣的方法。我一定会为将来的项目记住一个本地服务器的想法,但Mike的答案似乎更容易解决这个问题。 – 2010-07-30 18:10:39

2

您可以设置内容类型在data: URL,事情是这样的:

data:text/plain,this is some text 

然而,仍然存在浏览器自动将其呈现为文本的问题。你真的有两个选择,我可以看到。一种是你将类型设置为某种二进制类型,以便浏览器不尝试并呈现它,或者将类型设置为text/plain并让用户右键单击并另存为。也许here可以帮忙吗?

1

我一直在走这条路,我也想纯粹在客户端做。但是,这是不可能的。您可以毫不费力地触发保存对话框的唯一方法是发出HTTP POST请求,并让服务器以content-disposition标题响应。

我在my dusty old blog的代码片段中拥有您所需的功能。我有一个隐藏字段指向自定义HTTP处理程序的表单。 JavaScript抓住代码块的内部文本,将其放在隐藏字段中,并提交表单。服务器响应请求的全部内容以及所需的标题。没有刷新,你点击它,你会得到一个保存对话框。很棒!

+0

与'data:'URI联合使用'http-equiv'标题来模拟标题呢?这会起作用吗? – haxxerz 2012-08-02 03:26:38

相关问题