有没有办法在使用 data: URI 时指定建议的文件名?

Posted

技术标签:

【中文标题】有没有办法在使用 data: URI 时指定建议的文件名?【英文标题】:Is there any way to specify a suggested filename when using data: URI? 【发布时间】:2010-09-21 23:43:03 【问题描述】:

例如,如果您点击链接:

data:application/octet-stream;base64,SGVsbG8=

浏览器将提示您下载一个文件,该文件包含超链接本身中以 base64 形式保存的数据。有没有办法在标记中建议默认名称?如果没有,是否有 javascript 解决方案?

【问题讨论】:

可能与此问题无关,但如果这不是服务器或旧浏览器障碍,我建议使用 blob 的 & URL.createObjectURL 部分浏览器支持mediatype的可选参数“name”:data:application/pdf;name=document.pdf;base64,BASE64_DATA_ENCODED 我遇到了 Firefox pdf.js 的问题,如果它无法从数据 uri 中提取文件名,它在某些情况下往往会挂起。见***.com/questions/45585921/… @mems 哪些浏览器支持“name”参数?你能指点我一些参考文件吗? (我的 google-fu 让我失望了)。 @DimuDesigns 至少是当时的 Firefox。似乎不再是这种情况了。它与 MIME Con​​tent-Type (!= Content-Disposition) "name" 参数有关(不在 RFC 中?) 【参考方案1】:

使用download 属性:

<a download='FileName' href='your_url'>

The download attribute works on Chrome、Firefox、Edge、Opera、桌面版 Safari 10+、ios Safari 13+,而不是 IE11。

【讨论】:

@BioDesign:它甚至适用于 chrome 中的 data:URI。见:jsfiddle.net/pYpqW 但是你不能用window.location.replace来做。如果你例如想要创建一个 data:uri 或由window.URL.createObjectURL 生成的一个,并将其下载为文件,您必须创建一个 并单击它:jsfiddle.net/flyingsheep/wpQtH(不,$(...).click() 不起作用) 只有在所有浏览器都像 Chrome 一样... [叹息] @flyingsheep $('&lt;a href="data:text/plain,Test" download="test.txt"&gt;')[0].click() 似乎在这里工作正常(Chrome 23)(注意:我使用了原生的 click 方法,而不是 jQuery 的方法)。演示:jsfiddle.net/2zsRW @flyingsheep 似乎他们正在 Firefox 中执行同源策略“在 Firefox 20 中,此属性仅适用于指向同源资源的链接。” developer.mozilla.org/en-US/docs/Web/html/Element/a 在我的测试中,Chrome 没有这个限制。【参考方案2】:

如今,Chrome 让这一切变得非常简单:

function saveContent(fileContents, fileName)

    var link = document.createElement('a');
    link.download = fileName;
    link.href = 'data:,' + fileContents;
    link.click();

【讨论】:

我知道所有这些其他答案都在谈论什么,这在 Chrome 30 中首次尝试。 现在可以了,但并不总是那么容易。其中许多答案来自多年前。它们也适用于其他浏览器。 浏览器兼容性的完整列表请参考http://caniuse.com/#feat=download。 @tixastronauta:尽管该页面中有信息,但在我的 Firefox 44 中无法正常工作。在 Chrome 中运行良好。 48 嗨@Holf 有没有办法添加文件类型或扩展名,或者就像文件名一样简单?【参考方案3】:

仅 HTML: 使用 download 属性:

&lt;a download="logo.gif" href="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"&gt;Download transparent png&lt;/a&gt;

仅限Javascript:您可以使用此代码保存任何数据URI:

function saveAs(uri, filename) 
  var link = document.createElement('a');
  if (typeof link.download === 'string') 
    link.href = uri;
    link.download = filename;

    //Firefox requires the link to be in the body
    document.body.appendChild(link);
    
    //simulate click
    link.click();

    //remove the link when done
    document.body.removeChild(link);
   else 
    window.open(uri);
  


var file = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
saveAs(file, 'logo.gif');

Chrome、Firefox 和 Edge 13+ 将使用指定的文件名。

IE11、Edge 12 和 Safari 9(don't support the download attribute)将使用默认名称下载文件或者他们只会在新标签中显示,如果它是受支持的文件类型:图像、视频、音频文件……

【讨论】:

两个演示在 Chrome 38 中对我来说都可以正常工作(但它们应该在 Chrome 14+ 中工作) 为了更完整的解决方案,我建议使用downloadjs on npm 它适用于我,但之后浏览器页面会刷新。想知道如何防止这种情况发生? 文件大小在 chrome 中不可用 > 2MB 由于 chrome ***.com/questions/695151/… 的限制 限制属于data: URI,这就是问题提到的。这个答案也适用于 Blob 和其他任何有 URI 的东西【参考方案4】:

根据RFC 2397,不,没有。

&lt;a&gt; 元素中似乎也没有任何attribute 可以使用。

然而 HTML5 随后在 &lt;a&gt; 元素上引入了 download 属性,尽管在撰写本文时支持并不普遍(例如,不支持 MSIE)

【讨论】:

第二句话在撰写本文时是正确的,但 isn’t anymore。不过,到目前为止,它还没有被广泛实施。 见this comment了解更多信息:) @flyingsheep,它广泛实施。 我写那条评论还不是三年前 文件过长下载失败【参考方案5】:

我在 netwerk/protocol/data/nsDataHandler.cpp 中查看了一些 firefox 源代码

数据处理程序仅解析内容/类型和字符集,并查看是否存在“;base64” 在字符串中

rfc 没有指定文件名,至少 firefox 没有为它处理文件名, 代码生成一个随机名称加上“.part”

我还检查了 firefox 日志

[b2e140]: DOCSHELL 6e5ae00 InternalLoad data:application/octet-stream;base64,SGVsbG8=
[b2e140]: Found extension '' (filename is '', handling attachment: 0)
[b2e140]: HelperAppService::DoContent: mime 'application/octet-stream', extension ''
[b2e140]: Getting mimeinfo from type 'application/octet-stream' ext ''
[b2e140]: Extension lookup on '' found: 0x0
[b2e140]: Ext. lookup for '' found 0x0
[b2e140]: OS gave back 0x43609a0 - found: 0
[b2e140]: Searched extras (by type), rv 0x80004005
[b2e140]: MIME Info Summary: Type 'application/octet-stream', Primary Ext ''
[b2e140]: Type/Ext lookup found 0x43609a0

如果您想查看 mozilla 源代码,可以查看有趣的文件:

data uri handler: netwerk/protocol/data/nsDataHandler.cpp
where mozilla decides the filename: uriloader/exthandler/nsExternalHelperAppService.cpp
InternalLoad string in the log: docshell/base/nsDocShell.cpp

我认为您现在可以停止搜索解决方案,因为我怀疑没有:)

正如在此线程中注意到的那样,html5 具有 download 属性,它也适用于 firefox 20 http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#attr-hyperlink-download

【讨论】:

酷!虽然我不一定同意 Firefox 是存在的最终权威。 :)【参考方案6】:

以下 Javascript sn-p 通过使用链接的新“下载”属性并模拟点击在 Chrome 中运行。

function downloadWithName(uri, name) 
  var link = document.createElement("a");
  link.download = name;
  link.href = uri;
  link.click();

下面的例子展示了它的用途:

downloadWithName("data:,Hello%2C%20World!", "helloWorld.txt")

【讨论】:

这在 Firefox 中不起作用,我在下面添加了具有 Fx 兼容性的扩展答案。【参考方案7】:

没有。

整个目的是它是一个数据流,而不是一个文件。数据源不应该知道用户代理将其作为文件处理......而且它没有。

【讨论】:

data: 的目的是将内部数据块捏造成URL格式,而无需从基于协议的源读取它. @silex 答案中的链接表明,即使尚未实现,建议首选名称write 的能力也被认为是有用的。 @Alnitak:有用吗?绝对地。技术上合适吗?还是不服气。 :) @Tomalak 考虑加载数据和保存数据之间的区别——仅仅因为 blob 在数据中内联编码:URL 并不意味着它不应该有一个首选名称来保存它. 但是你关于它的“全部目的”的说法是错误的。 data: 是专门为允许(小)inline 内容以一种捏造在一起的 URL 格式出现的,这样它就可以被诸如图像标签之类的东西使用,而无需单独的 HTTP 请求。 HTML 表示 img src 属性的内容必须是 URL,这就是 RFC 2397 创建的内容。没有“数据源”。 @Alnitak:没错。没有数据源。没有上下文。 URI 数据。【参考方案8】:

您可以将下载属性添加到锚元素。

样本:

<a download="abcd.cer"
    href="data:application/stream;base64,MIIDhTC......">down</a>

【讨论】:

【参考方案9】:

使用service workers,这终于是真正意义上的可能了。

    创建一个虚假的 URL。例如 /saveAs/myPrettyName.jpg 在&lt;a href, &lt;img src 中使用 URL,window.open( url ),绝对是可以使用“真实”URL 完成的任何事情。 在 Worker 内部,捕获 fetch 事件,并以正确的数据进行响应。

浏览器现在会建议 myPrettyName.jpg,即使用户在新选项卡中打开文件并尝试将其保存在那里。就像文件来自服务器一样。

// In the service worker
self.addEventListener( 'fetch', function(e)

    if( e.request.url.startsWith( '/blobUri/' ) )
    
        // Logic to select correct dataUri, and return it as a Response
        e.respondWith( dataURLAsRequest );
    
);

【讨论】:

有趣!不过,目前支持似乎很浅:caniuse.com/#feat=serviceworkers 有没有办法用另一个指向文件的直接 url “响应”?【参考方案10】:

看看这个链接: http://lists.w3.org/Archives/Public/uri/2010Feb/0069.html

引用:

它甚至可以在末尾使用 ;base64 (如,不会导致问题) 像这样(至少在 Opera 中):

data:text/plain;charset=utf-8;headers=Content-Disposition%3A%20attachment%3B%20filename%3D%22with%20spaces.txt%22%0D%0AContent-Language%3A% 20en;base64,4oiaDQo%3D

在讨论的其余消息中也有一些信息。

【讨论】:

很遗憾这没有下载。 此讨论是针对数据 URI 格式的提议扩展 - 它尚未实现。 实现与否,在现有对任意参数的支持下,这将是一个很好的选择。【参考方案11】:

Google 代码上有一个对我有用的小变通脚本:

http://code.google.com/p/download-data-uri/

它添加一个包含数据的表单,提交它,然后再次删除该表单。哈基,但它为我完成了工作。需要 jQuery。

此主题在 Google 代码页面之前出现在 Google 中,我认为将链接也放在此处可能会有所帮助。

【讨论】:

有趣的脚本,但它确实需要服务器获取响应并将其发回,对吗? jsfiddle.net/hZySf 我不确定文件是从哪里生成的。该文件是否存储在 base64 编码中? (我对base64不太熟悉) @streetlight:“文件”(即数据)由 Javascript 生成。该项目的上下文(可能是这里的大多数)假设您有某种方法可以将所需的数据放入 JS 变量中。不同之处在于,该脚本不是通过data:... URI 将其呈现给用户,而是创建一个表单以将其发布到服务器。然后服务器可能会直接将其作为 HTTP“下载”响应回显(即使用适当的 Content-Disposition 标头指定文件名)。【参考方案12】:

这是一个基于 Holf 版本的 jQuery 版本,适用于 Chrome 和 Firefox,而他的版本似乎只适用于 Chrome。在身体上添加一些东西来做到这一点有点奇怪,但如果有人有更好的选择,我完全赞成。

var exportFileName = "export-" + filename;
$('<a></a>', 
    "download": exportFileName,
    "href": "data:," + JSON.stringify(exportData, null,5),
    "id": "exportDataID"
).appendTo("body")[0].click().remove();

【讨论】:

在 jQuery 1.11 中,由于 .remove() 而出现异常。我通过将$().appendTo() 分配给一个变量然后调用variable.click(); variable.remove() 来解决这个问题 @p0lar_bear 您应该使用任何 jQuery 获得该异常,因为从任何“jQuery 元素”获取 [0] 应该返回它所代表的第一个 DOM 元素,这实质上是“带你离开”jQuery。 您实际上根本不需要附加/删除元素——请参阅***.com/a/17311705/1037948的 cmets 【参考方案13】:

这个适用于 Firefox 43.0(旧版本未测试):

dl.js:

function download() 
  var msg="Hello world!";
  var blob = new File([msg], "hello.bin", "type": "application/octet-stream");

  var a = document.createElement("a");
  a.href = URL.createObjectURL(blob);

  window.location.href=a;

dl.html

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta charset="utf-8"/>
    <title>Test</title>
    <script type="text/javascript" src="dl.js"></script>
</head>

<body>
<button id="create" type="button" onclick="download();">Download</button>
</body>
</html>

如果单击按钮,它会提供一个名为 hello.bin 的文件供下载。诀窍是使用 File 而不是 Blob

参考:https://developer.mozilla.org/de/docs/Web/API/File

【讨论】:

【参考方案14】:

(此答案已被新技术弃用,但出于历史兴趣将保留在这里。)

这有点骇人听闻,但我以前也遇到过同样的情况。我在 javascript 中动态生成一个文本文件,并希望通过使用 data-URI 对其进行编码来提供它以供下载。

这可以通过minor主要的用户干预来实现。生成链接&lt;a href="data:..."&gt;right-click me and select "Save Link As..." and save as "example.txt"&lt;/a&gt;。正如我所说,这很不优雅,但如果您不需要专业的解决方案,它就可以工作。

首先使用 flash 将名称复制到剪贴板可以减轻这种痛苦。当然,如果您让自己使用 Flash 或 Java(我认为现在浏览器支持越来越少?),您可能会找到另一种方法。

【讨论】:

这不是解决方案,也不符合要求。对不起。 大声笑@“次要用户干预”。让用户为你做所有事情并不是“轻微的用户干预”。 将此与***.com/questions/17311645/… 结合以触发生成的链接,您不需要用户干预。您可以指定HTML5 download attribute 来建议many other answers 提到的名称。 这是 Safari 的一个很好的解决方法。使用 Modernizr 检测何时不支持下载属性并更新链接文本!【参考方案15】:

&lt;a href=.. download=.. &gt; 适用于左键单击和右键单击-> 将链接另存为..,

&lt;img src=.. download=.. &gt; 不适用于右键单击 -> 将图像另存为.. ,建议使用“Download.jped”。

如果你将两者结合起来:&lt;a href=.. download=..&gt;&lt;img src=..&gt;&lt;/a&gt;

它适用于左键单击,右键单击 -> 将链接另存为..,右键单击 -> 将图像另存为..

你必须写两次 data-uri(href 和 src),所以对于大的图像文件,最好用 javascript 复制 uri。

使用 Chrome/Edge 88 测试

【讨论】:

【参考方案16】:
var isIE = /*@cc_on!@*/false || !!document.documentMode; // At least IE6
var sessionId ='\n';
var token = '\n';
var caseId = CaseIDNumber + '\n';
var url = casewebUrl+'\n';
var uri = sessionId + token + caseId + url;//data in file
var fileName = "file.i4cvf";// any file name with any extension
if (isIE)
    
            var fileData = ['\ufeff' + uri];
            var blobObject = new Blob(fileData);
            window.navigator.msSaveOrOpenBlob(blobObject, fileName);
    
    else //chrome
    
        window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
         window.requestFileSystem(window.TEMPORARY, 1024 * 1024, function (fs) 
            fs.root.getFile(fileName,  create: true , function (fileEntry)  
                fileEntry.createWriter(function (fileWriter) 
                    var fileData = ['\ufeff' + uri];
                    var blob = new Blob(fileData);
                    fileWriter.addEventListener("writeend", function () 
                        var fileUrl = fileEntry.toURL();
                        var link = document.createElement('a');
                        link.href = fileUrl;
                        link.download = fileName;
                        document.body.appendChild(link);
                        link.click();
                        document.body.removeChild(link);
                    , false);
                    fileWriter.write(blob);
                , function ()  );
            , function ()  );
         , function ()  );
    

【讨论】:

请为您的答案添加更详细的解释 - ***.com/help/how-to-answer 这个答案很垃圾【参考方案17】:

您实际上可以在 Chrome 和 FireFox 中实现这一点。

试试下面的网址,它会下载使用过的代码。

data:text/html;base64,PGEgaHJlZj0iZGF0YTp0ZXh0L2h0bWw7YmFzZTY0LFBHRWdhSEpsWmowaVVGVlVYMFJCVkVGZlZWSkpYMGhGVWtVaUlHUnZkMjVzYjJGa1BTSjBaWE4wTG1oMGJXd2lQZ284YzJOeWFYQjBQZ3BrYjJOMWJXVnVkQzV4ZFdWeWVWTmxiR1ZqZEc5eUtDZGhKeWt1WTJ4cFkyc29LVHNLUEM5elkzSnBjSFErIiBkb3dubG9hZD0idGVzdC5odG1sIj4KPHNjcmlwdD4KZG9jdW1lbnQucXVlcnlTZWxlY3RvcignYScpLmNsaWNrKCk7Cjwvc2NyaXB0Pg==

【讨论】:

以上是关于有没有办法在使用 data: URI 时指定建议的文件名?的主要内容,如果未能解决你的问题,请参考以下文章

从 ContentObserver 获取触发器

有没有办法在 Spring Data @Query 注释值中使用常量?

如何从 Uri 获取位图?

无效参数:在 URI 文件中未指定主机:///null

是否有办法在春季为自定义依赖项找出application.properties文件的属性名?

当提供者不支持自定义 URI 方案时如何重定向到 iOS