在没有任何服务器请求的情况下触发文件下载

时间:2010-07-28 22:58:28

标签: javascript html

问候,

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

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

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

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

我一直在这个网站上搜索,在WHATWG和W3C网站上以及在网上搜索都没有成功。这可行吗?

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

如果只有某种方法可以将data:网址与“内容处理”类型的提示相结合,那么事情就会非常顺利。

此致 Herenvardo

4 个答案:

答案 0 :(得分:2)

不幸的是,这不是普通浏览器功能所能做到的。像flash或特定浏览器这样的插件可以满足您的需求,但javascript中的安全限制不允许您下载在浏览器中创建的任意数据。

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

答案 1 :(得分:2)

这个解决方案有点令人费解,但可以满足您的需求,也许这是一个选择。

创建一个自定义Web服务器,它只返回任何GET或POST的内容为text / plain。

将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();
    }

    }
}

答案 2 :(得分:2)

您可以在data:网址中设置内容类型,如下所示:

data:text/plain,this is some text

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

答案 3 :(得分:1)

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

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