无需任何服务器请求即可触发文件下载

问题描述 投票:0回答:4

问候,

我正在开发一个基于 JS 的应用程序,它可以完成一些复杂的工作并在

<div>
上记录一些信息(实际上,最多数百行)。

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

<div>

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

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

我一直在这个网站、WHATWG 和 W3C 网站以及整个网络上进行搜索,但没有成功。这到底可行吗?

我得到的最接近的是使用

data:
url。我的第一次尝试执行 POST 操作,无法通过内容类型,因此它会退回到 UA 的启发式方法。我通过将
<a>
链接设计为看起来像按钮并为其赋予
type
属性,效果稍好一些,但是 UA 会表现得太聪明并渲染内容而不是保存(并要求用户保存文件)在该步骤中从浏览器进行的操作比采用复制粘贴方法更糟糕,因为浏览器之间的页面保存差异很大)。

如果有某种方法将

data:
url 与“内容处置”之类的提示结合起来,事情就可以非常顺利。

问候, 赫伦瓦尔多

javascript html
4个回答
2
投票

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

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


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

    }
}

2
投票

您可以在

data:
URL 中设置内容类型,如下所示:

data:text/plain,this is some text

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


1
投票

我一直在这条路上走下去,我也想纯粹在客户端做。 但是,这是不可能的。您可以轻松触发保存对话框的唯一方法是发出 HTTP POST 请求,并让服务器使用

content-disposition
标头进行响应。

我在我布满灰尘的旧博客上的代码片段中有你想要的功能。 我有一个表单,其中一个隐藏字段指向自定义 HTTP 处理程序。 JavaScript 抓取代码块的内部文本,将其放入隐藏字段中,然后提交表单。 服务器响应请求的整个正文以及所需的标头。 无需刷新,单击它就会出现一个保存对话框。 效果很好!

© www.soinside.com 2019 - 2024. All rights reserved.