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

Javascript 在没有任何服务器请求的情况下触发文件下载,javascript,html,Javascript,Html,您好 我正在开发一个基于JS的应用程序,它可以做一些复杂的工作,并在上记录一些信息(实际上,多达数百行) 我的目标是有一个“保存日志”按钮,它触发浏览器的下载对话框来保存我的日志内容 更简单地说,此功能的要求如下: 最终用户必须完全控制该文件。他/她应该能够将其保存/存档以备将来参考,将其发送给支持部门以获得解决某些问题的帮助,将其加载回应用程序中,等等。因此HTML5的Web存储API在这里没有帮助(数据将保存到浏览器定义的位置,并且除了创建它的JS之外,不容易检索) 应用程序必须能够脱机工

您好

我正在开发一个基于JS的应用程序,它可以做一些复杂的工作,并在
上记录一些信息(实际上,多达数百行)

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

更简单地说,此功能的要求如下:

  • 最终用户必须完全控制该文件。他/她应该能够将其保存/存档以备将来参考,将其发送给支持部门以获得解决某些问题的帮助,将其加载回应用程序中,等等。因此HTML5的Web存储API在这里没有帮助(数据将保存到浏览器定义的位置,并且除了创建它的JS之外,不容易检索)
  • 应用程序必须能够脱机工作(至少在某些情况下)。这就是为什么我放弃了将数据发布到服务器以使用“contentdisposition”标题取回数据的想法
  • 文件应正确标记为
    text/plain
    ,以便浏览器可以建议默认操作(如“在记事本上打开”),就像普通文件下载一样。这可以看作是第一个需求的一个特定方面
  • 告诉用户将
    的内容复制粘贴到一个文本编辑器中,然后从那里保存下来,这绝对是可怕的,这正是我试图避免的原因
我一直在这个网站上搜索,在WHATWG和W3C网站上搜索,在网络上搜索都没有成功。这完全可行吗

我得到的最接近的方法是使用
data:
url。我的第一次尝试,执行POST操作,无法获得内容类型,因此它将退回到UA的启发式。我把
链接设计成按钮的样式,并给它一个
类型
属性,这样做稍微好一点,但是UA会玩得太聪明,渲染内容而不是保存(在这一步中,要求用户从浏览器保存文件比使用复制粘贴方法更糟糕,因为不同浏览器之间的页面保存差异很大)

如果有某种方法可以将
数据:
url与“内容处置”(如提示)结合起来,事情就会变得非常顺利

问候,,
Herenvardo

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


此外,并非所有浏览器/版本组合都支持“数据”url。我不确定您的用户是否受限于他们使用的浏览器,但这可能会限制您使用该解决方案的能力。

此解决方案有点复杂,但可以满足您的需要,也许这是一个选项

创建一个自定义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();
    }

    }
}

您可以在
数据:
URL中设置内容类型,如下所示:

data:text/plain,this is some text

但是,这仍然存在浏览器自动将其呈现为文本的问题。我可以看到您确实有两个选项。一个是您将类型设置为某种二进制类型,这样浏览器就不会尝试呈现它,或者您将类型设置为text/plain,让用户右键单击并另存为。也许有什么可以帮助?

我一直在走这条路,我也希望完全在客户端完成。但是,这是不可能的。触发保存对话框而不引起任何麻烦的唯一方法是发出HTTP POST请求,并让服务器使用
内容处置
标题进行响应


我在上的代码片段中提供了您所需的功能。我有一个表单,其中一个隐藏字段指向自定义HTTP处理程序。Javascript获取代码块的内部文本,将其放入隐藏字段中,然后提交表单。服务器使用请求的整个主体以及所需的标题进行响应。如果不刷新,请单击它然后你会看到一个保存对话框。效果很好!

使用像Flash这样的插件是不可能的吗?我不知道是否可以使用标准HTML,但如果Flash是一个选项,那就很容易了…我有一个类似的问题,但只有一个答案。不过我认为这不可能。问题解决了吗“用代码复制到剪贴板,并告诉用户将其粘贴到记事本(或最喜爱的文本编辑器)”想法出现了吗?剪贴板可以处理兆字节,但记事本可能会被几兆字节阻塞。另一方面:请看,谢谢!似乎插件(或Flash)-基于数据的方法是满足所有要求的唯一方法。另一方面,对“数据”的支持不是什么大问题:整个应用程序依赖于大量HTML5功能,因此已经有了大量的浏览器需求,需要对“数据”的支持并不是什么大问题。此外,Silverlight可能是一个可行的选择。对于这样的应用程序,+1一个有趣的方法。我肯定会在未来的项目中记住本地服务器的想法,但是Mike的回答似乎更容易解决这个问题。使用
http equiv
头和
data:
URI来模拟头怎么样?这样行吗?