【问题标题】:javascript or jquery download large file as URIjavascript 或 jquery 将大文件下载为 URI
【发布时间】:2018-06-20 08:53:36
【问题描述】:

我正在开发一个 Web 应用程序,它需要的一项功能是能够以交互方式下载一个相当大的文件 - 该文件在服务器上不存在 - 并且完全由从数据库动态加载的数据组成。

目前我正在使用以下代码(不会为您运行,但您可以理解) 我在其中添加了一个带有文件名的文本框,然后是一个隐藏的文本区域,其中包含 json 样式下载所需的所有文本,然后链接到一个尝试 URI 下载的函数。

有趣的是,当在 chrome 中运行时,我得到一个页面说 URI 太长并且它无法工作等,但文件仍然被下载。

"提交的 URI 太大! 请求的 URL 的长度超过了此服务器的容量限制。无法处理该请求。 如果您认为这是服务器错误,请联系站长。”

总之,烦人的是: 允许这些下载的页面使用前一页的帖子/获取 - 因此后退按钮不可用,因为它为我们提供了:

"确认表格重新提交 此网页需要您之前输入的数据才能正确显示。您可以再次发送此数据,但这样做会重复此页面之前执行的任何操作。”

页面 - 我想做的是将这些 URI 下载生成到一个新选项卡中,因此不需要返回按钮,尽管添加目标空白没有帮助

也很有趣——如上所示,我确实有一个“全部下载”的功能——它适用于我在 xampp 服务器上本地运行的东西,在谷歌浏览器上——但是那些我正在构建应用程序以报告按钮不起作用对他们来说(他们在使用 safari 的 mac 上,还没有机会亲眼看到这个并收集信息 - 所以虽然我不希望用我有限的信息来回答这个问题,但我希望有人可能有一个想法!)

代码:

< script >
  function download(filename, text) {
    var element = document.createElement('a');
    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
    // I tried addin this but no new tab appeared!
    //element.target = "_blank:";
    element.setAttribute('download', filename);

    element.style.display = 'none';
    document.body.appendChild(element);

    element.click();

    document.body.removeChild(element);
  }

function download_all() {
  var nameElements = document.getElementsByName("name");
  var valueElements = document.getElementsByName("text");

  for (i = 0; i < nameElements.length; i++) {
    console.log(nameElements[i].value);
    console.log(valueElements[i].value);

    download(nameElements[i].value, valueElements[i].value);
  }
} <
/script>

echo "
<form onsubmit=\ "download(this['name'].value, this['text'].value)\" class=\ "form-group\">"; echo "<label for=\ "name\">Download Title</label>"; echo "<input type=\ "text\" name=\ "name\" size=\ "40\" value=\ "" . $m[ 'name'] . ".json" . "\" class=\ "form-inline\">"; //hidden=\"hidden\"> after text echo "<textarea name=\ "text\" hidden=\
    "hidden\">" . $json_meal_data . "</textarea>"; echo "<input type=\ "submit\" value=\ "Download\" class=\ "btn-primary\">"; echo "</form>"; echo "<br>"; echo "<br>";

另外值得注意的是,我在上面的 sn-ps 中包含了 Download All 功能。 奇怪的是,在 Chrome 中运行 download all 会下载所有文件,但在 Safari 中运行只会下载 1 个文件。

【问题讨论】:

  • 您是否尝试将数据放入 blob 并下载?使用 URL.createObjectURL 从 blob 创建 url。至于全部下载,某些浏览器(如 Chrome)会阻止多次连续下载,用户需要允许它才能工作(在 chrome 中,您可以通过单击地址栏末尾的图标来访问它)
  • 您可以提供.zip 文件供下载,其中可能包含多个文件和文件夹,请参阅Multiple download links to one zip file before download javascript
  • @PatrickEvans 我必须检查浏览器并下载所有内容 - 如前所述,我还没有亲眼看到它失败,因为它在我的开发环境中的 chrome 中对我有用。我还没有尝试将它放到一个 blob 中并使用这种方法——我以前从未听说过。我可以试一试 - 但请记住,这些文件每个大约 25mb - 不确定这是否可行?
  • @guest271314 看了几眼,文件似乎需要存在?没有要下载的源文件,该文件是在页面加载时生成的,只是文本区域中保存的一堆文本
  • 不确定是什么问题?你想达到什么目的?您可以使用ReadableStream 读取&lt;textarea&gt; 元素的.textContent,然后下载文件,请参阅How to solve Uncaught RangeError when download large size json

标签: javascript jquery download uri


【解决方案1】:

您在 XAMPP 中传递的 URL 太长。 XAMPP 代表 Apache。在阿帕奇, 最大 URL 长度约为 4,000 个字符,之后Apache 会产生“413 Entity Too Large”错误。

我同意@PatrickEvans 的观点,最好使用URL.createObjectURLURL.createObjectURL() 可用于构造和解析 URL。 URL.createObjectURL() 具体来说,可用于创建对文件或 Blob 的引用。与 base64 编码的数据 URL 不同,它不包含对象的实际数据,而是包含一个引用。

这样做的好处是它非常快。以前,我们必须实例化一个FileReader 实例并将整个文件作为base64 数据URL 读取,这需要时间和大量内存。使用createObjectURL(),可以立即获得结果,让我们能够执行诸如将图像数据读取到画布等操作。

您可以在下面的演示中看到。两个链接是相同的。但是如果您检查Without createObjectURL 链接href 属性具有too large to edit 但在With createObjectURL 链接中您可以编辑它,因为创建它我使用URL.createObjectURL()

Online demo (jsFiddle)

【讨论】:

  • 我一定已经尝试过我得到的所有其他建议组合 - 从防止链接默认值,到制作 blob,到我的 json 等 - 但这是我第一次收到一个可行的小提琴示例建立。在我尝试的组合尝试中: var blob = new Blob([text]);saveAs(blob, filename);使用文件保护程序 - 但我认为我创建的 blob 不如我应该的那样 - 而且我仍然会更改页面。使用您的小提琴,我可以在这里和那里进行调整以适应我的设置。所以谢谢你 - 终于成功了:)
  • @aescript 很高兴能为您提供帮助:)
  • 享受你的赏金吧!
【解决方案2】:

您不需要将元素附加到文档。并且避免使用 base64,因为它比 Blob 大 37%。

function download(filename, text) {
  var element = document.createElement('a');
  var blob = new Blob([text], {type: "octet/stream"})
  var url = URL.createObjectURL(blob);
  element.setAttribute('href', url);
  element.setAttribute('download', filename);
  element.click();
}

【讨论】:

  • 这不会触发浏览器保护非用户启动的下载吗?我认为这往往会在浏览器中敲响警钟。您应该更新以涵盖这可能会受到保护,并可能举一个使用 onMouseDown 在元素上设置它的示例,以便当浏览器触发鼠标向上和单击时,它会开始下载。
【解决方案3】:

可能发生的情况是您实际上是在填充浏览器 URL 并向服务器提交 GET 请求。

GET 请求限制了它们可以传输到服务器的数据量,因此 URI 太长。 (相比之下,POST 允许更大的有效负载,并且仅受服务器设置的限制)

您可以在此处找到有关浏览器锚长度限制的更多信息:

What is the maximum length of a URL in different browsers?

https://weblogs.asp.net/mschwarz/post-vs-get

【讨论】:

  • 为什么有人会首先使用带有大负载的 GET?如果他们无论如何都提交带有有效负载的东西,那么使用 POST 不是更有意义吗?
  • 因为一些开发人员在设计他们的 API 方面缺乏经验?某些 GET 请求可能包含过滤条件。想想 google.com,当您运行搜索时,他们为您的 get 请求提供了“q”查询字符串参数。你可以在那里放置一个巨大的搜索词或大量的需求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-12
  • 2012-10-03
  • 2014-02-06
  • 1970-01-01
  • 2018-11-02
  • 2021-06-21
  • 2021-12-18
相关资源
最近更新 更多