(HTML) 当点击时下载 PDF 文件而不是在浏览器中打开它们

157
我想知道如何使PDF文件链接可下载而不是在浏览器中打开?在HTML中如何实现这一点?(我想这是通过JavaScript或其他方式完成的)。

4
据我所知,这种行为不可编写脚本。大多数浏览器都有自己的设置,用于控制下载特定文件类型时的行为。 - Bart
1
从HTML5开始,OP应该将正确答案更新为Sarim的答案。 - Omar Tariq
这个问题在这里也得到了回答: https://dev59.com/znA75IYBdhLWcg3w1sz2#30714824 - intrepidis
16个回答

162

如果支持的话,最好采用这个解决方案。以下是检查是否支持的方法:if ("download" in document.createElement("a")){ ... } - pmrotule
我在下面添加了另一个答案(虽然是不好的 hack 方法),尽管这仍然是首选方式,但对于不支持的浏览器,也许可以提供 hack 方法。 - Sarim
有没有办法可以指定 PDF 的文本而不是提及文件路径?我需要从 div html 创建 PDF,但我不希望打开另一个窗口,下载应该像这个答案中一样无缝。 - T.Adak
1
截至2019年8月,浏览器对此功能的支持似乎得到了增强,请参见:https://www.w3schools.com/tags/att_a_download.asp - user6057915
20
请注意,download属性仅支持同源请求。 - Quentin

98

只有通过服务器端设置HTTP响应头才能实现这一点。具体来说,

Content-Disposition: attachment; filename=fname.ext

3
这是完美的答案 - 只需找到适当的服务器端语言来实现它。 - user158017
Apache 示例。Flask 示例。 - Bob Stein
不幸的是,即使内容设置为“附件”,iOS仍然只会预览而不会下载PDF文件。 - Jorn van de Beek
目前它不起作用。文件仍然被打开了。 - Vyshnia

52
现在有HTML 5 download属性可以处理这个问题。
我同意,认为Sarim的回答很好(如果OP回来的话,它可能应该成为被选择的答案)。然而,这个答案仍然是处理它的可靠方法(正如Yiğit Yener的回答所指出的,奇怪的是人们同意)。虽然下载属性已经得到支持,但仍然不稳定:

http://caniuse.com/#feat=download


10

你需要使用一个PHP脚本(或其他服务器端语言)来实现此功能。

<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');

// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');

// The PDF source is in original.pdf
readfile('original.pdf');
?>

并使用htaccess重定向(重写)到PHP文件,而不是PDF文件。


嗯,当我直接打开php文件时,它的工作非常好。但是当我尝试使用重定向时,比如这样: Redirect 301 /_PDFs/Catalogue.pdf http://www.example.com/_PDFs/___download_the_catalogue_instead_opening.php 并尝试打开pdf文件时,它仍然在浏览器中打开原始文件,而不是下载重命名的版本... - ellockie
更新:当没有直接调用的文件(如我的示例中的“Catalogue.pdf”)时,它可以正常工作。然后重定向就可以完美地工作了。谢谢! - ellockie

9
您可以使用

标签


Response.AddHeader("Content-disposition", "attachment; filename=" + Name);

请看这个例子:

http://www.codeproject.com/KB/aspnet/textfile.aspx

这是针对ASP.NET的。我相信你可以在所有其他服务器端语言中找到类似的解决方案。然而,据我所知,没有JavaScript解决方案。


这是答案(以及相关的PHP答案)。关键是必须编辑HTTP响应头。 - user158017

8
当你想要直接从浏览器下载任何图像或pdf文件,而不是在新标签页中打开它时,你可以使用JavaScript设置创建动态链接的download属性的值。
    var path= "your file path will be here"; 
    var save = document.createElement('a');  
    save.href = filePath; 
    save.download = "Your file name here"; 
    save.target = '_blank'; 
    var event = document.createEvent('Event');
    event.initEvent('click', true, true); 
    save.dispatchEvent(event);
   (window.URL || window.webkitURL).revokeObjectURL(save.href);

在新的Chrome更新中,有时事件不起作用。为此,可以使用以下代码:

  var path= "your file path will be here"; 
    var save = document.createElement('a');  
    save.href = filePath; 
    save.download = "Your file name here"; 
    save.target = '_blank'; 
    document.body.appendChild(save);
    save.click();
    document.body.removeChild(save);

在 Firefox 和 Internet Explorer 浏览器中,添加子元素和删除子元素非常有用。但是在 Chrome 中,无需添加和删除子元素即可正常工作。


4

如果没有html5属性,可以使用php来实现:

创建名为download.php的php文件,并使用以下代码:

<?php
ob_start();
$file = "yourPDF.pdf"

if (file_exists($file)) 
{
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename='.basename($file));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    ob_clean();
    flush();
    readfile($file);
    exit();
}

现在如果你想自动开始下载PDF,请编写以下javascript代码:
<script>window.location = "download.php";</script>

如果您想在链接上使用此功能,请使用以下内容...
<a href='javascript:window.location = "download.php"'>
    Download it!
</a>

4
提醒您,在使用URL参数时需小心。例如:$file = $_GET['$file'];,因为有人可以通过 download.php?file=../../../wp-config.php 或其他资源来调用。额外的检查文件扩展名、MIME类型和允许下载的路径(并去除如"../"等不必要内容)非常重要! - Giel Berkers
是我还是使用 <a href='javascript...'> 和直接在 <a href='download.php'> 中放置链接完全相同? - allan.simon

4

我曾经尝试过使用创建a DOM元素并设置download属性的方法解决问题,但在某些浏览器中仍会弹出警告(也许它们在2021年变得更加严格了)。

将pdf的mime类型添加到href属性中可以解决浏览器弹窗警告,但却使文件损坏无法打开。

在2021年,您可以使用Edhowler建议的XMLHttpRequest来下载PDF文件,而不需要PHP或Apache设置并且没有浏览器警告。他的代码示例使用npm库,但以下是如何只使用js完成该操作:

/**
 * Download a file without browser popup warning
 * @param {string} url The url of the file to download
 * @param {string} filename Set a new filename for the downloaded file (optional)
 */
const downloadFile = (url, filename = '') => {
  if (filename.length === 0) filename = url.split('/').pop();
  const req = new XMLHttpRequest();
  req.open('GET', url, true);
  req.responseType = 'blob';
  req.onload = function () {
    const blob = new Blob([req.response], {
      type: 'application/pdf',
    });

    const isIE = false || !!document.documentMode;
    if (isIE) {
      window.navigator.msSaveBlob(blob, filename);
    } else {
      const windowUrl = window.URL || window.webkitURL;
      const href = windowUrl.createObjectURL(blob);
      const a = document.createElement('a');
      a.setAttribute('download', filename);
      a.setAttribute('href', href);
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
    }
  };
  req.send();
};

downloadFile('https://domain.tld/file.pdf');

如果需要支持不支持 ES6+ 的浏览器,请使用像 Babel 这样的转译器。


这假设CORS已启用... - Cristian E.
你能详细说明一下吗,Cristian?我认为你是正确的,假设你的文件不在同一台服务器上。 - jnaklaas

3
作为HTML5方法(我的上一个答案)并不适用于所有浏览器,这里提供另一种略微“hack”的方法。
此解决方案要求您从相同的域名服务中获取所需文件,或具有CORS权限。
1. 首先通过XMLHttpRequest(Ajax)下载文件内容。 2. 然后通过对文件内容进行base64编码并将媒体类型设置为“application/octet-stream”来创建数据URI。结果应该看起来像:
data:application/octet-stream;base64,SGVsbG8sIFdvcmxkIQ%3D%3D
3. 现在设置location.href = data。这将导致浏览器下载该文件。不幸的是,您无法以这种方式设置文件名或扩展名。调整媒体类型可能会产生一些效果。
详情请参见:https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs

3

这是在另一个域中下载的最佳JavaScript解决方案。 - Edhowler
@Edhowler,你有这方面的例子吗? - Aljohn Yamaro
我在新帖中回答了。 - Edhowler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接