在HTML中点击文本链接时强制打开“另存为”弹出窗口以下载PDF文件。

210

我在我的网站上有一些大型PDF目录,我需要将它们链接为下载。当我使用谷歌搜索时,我发现了下面这个方法。它应该在链接单击时打开“另存为...”弹出窗口...

 <head>
    <meta name="content-disposition" content="inline; filename=filename.pdf">
    ...

但是它不起作用 :/ 当我按照以下方式链接到文件时,它只会链接到文件并尝试打开该文件。

    <a href="filename.pdf" title="Filie Name">File name</a>

更新(根据下面的答案):

我发现没有100%可靠的跨浏览器解决方案。可能最好的方法是使用下面列出的其中一个网页服务,并提供下载链接...


1
不要提供PDF文件的MIME类型。 - bhups
我尝试了你更新的解决方案artmania,但在Safari中仍然出现了我一直遇到的同样问题。我在浏览器窗口中看到了类似PDF的东西,只有当我点击底部的“预览”或“下载”选项卡时,才能得到我非常需要的搜索功能。 - heathwaller
如何自动强制下载PDF?你可以使用以下代码来自动强制下载PDF文件:header('Content-Type: application/pdf'); header('Content-Disposition: attachment; filename="downloaded.pdf"'); readfile("path/to/your/file.pdf");请确保将“path/to/your/file.pdf”替换为您的PDF文件的实际路径。 - Ciro Santilli OurBigBook.com
将以下与编程有关的内容从英语翻译为中文。仅返回翻译后的文本:类似但不特定于文件类型:https://dev59.com/EHM_5IYBdhLWcg3wPAjT - Ciro Santilli OurBigBook.com
19个回答

3
如果您需要在页面上强制下载单个链接,一个非常简单的方法是使用HTML5 download属性在href链接中。
请参见:http://davidwalsh.name/download-attribute 使用此方法,您可以重命名用户将要下载的文件,并同时强制进行下载。
关于这种做法是否好还存在争议,但在我的情况下,我有一个用于PDF文件的嵌入式查看器,该查看器没有提供下载链接,因此我必须单独提供一个链接。在这里,我想确保用户不会在Web浏览器中打开PDF文件,这可能会令人困惑。
这不一定会打开“另存为”对话框,但会直接将链接下载到预设的下载目标位置。当然,如果您正在为其他人创建网站,并需要让他们手动编写链接属性,则这可能是一个坏主意,但如果有办法将属性添加到链接中,则这可以是一个轻量级的解决方案。

2

这是一篇旧文章,但我在这里提供我的JavaScript解决方案,使用了jQuery库。

<script>
(function($){
    var download = [];
    $('a.force-download, .force-download a').each(function(){
        // Collect info
        var $this = $(this),
            $href = $this.attr('href'),
            $split = $href.split('/'),
            $name = document.title.replace(/[\W_]/gi, '-').replace(/-{2,}/g, '-'); // get title and clean it for the URL

        // Get filename from URL
        if($split[($split.length-1)])
        {
            $tmp = $split[($split.length-1)];
            $tmp = $tmp.split('.');
            $name = $tmp[0].replace(/[\W_]/gi, '-').replace(/-{2,}/g, '-');
        }

        // If name already exists, put timestamp there
        if($.inArray($name, download) > -1)
        {
            $name = $name + '-' + Date.now().replace(/[\W]/gi, '-');
        }

        $(this).attr("download", $name);
        download.push($name);
    });
}(jQuery || window.jQuery))
</script>

您只需要在 标签中使用force-download类,就会自动强制下载。您还可以将其添加到父div中,并将拾取其中的所有链接。

示例:

<a href="/some/good/url/Post-Injection_Post-Surgery_Instructions.pdf" class="force-download" target="_blank">Download PDF</a>

这对WordPress和任何其他系统或自定义网站都非常有用。


2

直到所有浏览器都实现了“download”属性,服务器端解决方案更为兼容。

一个Python示例可以是文件存储的自定义HTTP请求处理程序。指向文件存储的链接生成方式如下:

http://www.myfilestore.com/filestore/13/130787e71/download_as/desiredName.pdf

以下是代码:

class HTTPFilestoreHandler(SimpleHTTPRequestHandler):

    def __init__(self, fs_path, *args):
        self.fs_path = fs_path                          # Filestore path
        SimpleHTTPRequestHandler.__init__(self, *args)

    def send_head(self):
        # Overwrite SimpleHTTPRequestHandler.send_head to force download name
        path = self.path
        get_index = (path == '/')
        self.log_message("path: %s" % path)
        if '/download_as/' in path:
            p_parts = path.split('/download_as/')
            assert len(p_parts) == 2, 'Bad download link:' + path
            path, download_as = p_parts
        path = self.translate_path(path )
        f = None
        if os.path.isdir(path):
            if not self.path.endswith('/'):
                # Redirect browser - doing basically what Apache does
                self.send_response(301)
                self.send_header("Location", self.path + "/")
                self.end_headers()
                return None
            else:
                return self.list_directory(path)
        ctype = self.guess_type(path)
        try:
            f = open(path, 'rb')
        except IOError:
            self.send_error(404, "File not found")
            return None
        self.send_response(200)
        self.send_header("Content-type", ctype)
        fs = os.fstat(f.fileno())
        self.send_header("Expires", '0')
        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
        self.send_header("Cache-Control", 'must-revalidate, post-check=0, pre-check=0')
        self.send_header("Content-Transfer-Encoding", 'binary')
        if download_as:
            self.send_header("Content-Disposition", 'attachment; filename="%s"' % download_as)
        self.send_header("Content-Length", str(fs[6]))
        self.send_header("Connection", 'close')
        self.end_headers()
        return f


class HTTPFilestoreServer:

    def __init__(self, fs_path, server_address):
        def handler(*args):
            newHandler = HTTPFilestoreHandler(fs_path, *args)
            newHandler.protocol_version = "HTTP/1.0"
        self.server = BaseHTTPServer.HTTPServer(server_address, handler)

    def serve_forever(self, *args):
        self.server.serve_forever(*args)


def start_server(fs_path, ip_address, port):
    server_address = (ip_address, port)
    httpd = HTTPFilestoreServer(fs_path, server_address)

    sa = httpd.server.socket.getsockname()
    print "Serving HTTP on", sa[0], "port", sa[1], "..."
    httpd.serve_forever()

2
在响应头中添加Content-Disposition:attachment;,后跟文件名。删除Meta Content-Disposition;Inline;,这将在同一窗口中打开文档。
在Java中设置如下:
response.setHeader("Content-Disposition", "attachment;filename=test.jpg");

非常感谢,这对我来说解决了问题(在Python/Zope中)! - Georg Pfolz

1
在HTML代码中的文件名后面,我添加了?forcedownload=1。这是我触发保存或下载对话框最简单的方法。

这个解决方案和@j-beda建议的下载属性对我很有效。请注意,我遇到了一个问题,Chrome自动打开.dot和.doc文件而不是显示下载框。 - jona

0

我刚遇到了一个非常相似的问题,需要创建指向ZIP文件内部文件的下载链接。

我首先尝试创建临时文件,然后提供临时文件的链接,但我发现一些浏览器只会显示内容(CSV Excel文件),而不是提供下载。最终,我通过使用servlet找到了解决方案。它在Tomcat和GlassFish上都可以工作,并且我在Internet Explorer 10和Chrome上进行了尝试。

servlet以ZIP文件的完整路径名和应下载的zip内文件的名称作为输入。

在我的JSP文件中,我有一个表格显示ZIP文件中的所有文件,并带有链接,如:onclick='download?zip=<%=zip%>&csv=<%=csv%>'

servlet代码在download.java中:

package myServlet;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.zip.*;
import java.util.*;

// Extend HttpServlet class
public class download extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        PrintWriter out = response.getWriter(); // now we can write to the client

        String filename = request.getParameter("csv");
        String zipfile = request.getParameter("zip");

        String aLine = "";

        response.setContentType("application/x-download");
        response.setHeader( "Content-Disposition", "attachment; filename=" + filename); // Force 'save-as'
        ZipFile zip = new ZipFile(zipfile);
        for (Enumeration e = zip.entries(); e.hasMoreElements();) {
            ZipEntry entry = (ZipEntry) e.nextElement();
            if(entry.toString().equals(filename)) {
                InputStream is = zip.getInputStream(entry);
                BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"), 65536);
                while ((aLine = br.readLine()) != null) {
                    out.println(aLine);
                }
                is.close();
                break;
            }
        }
    }
}

在Tomcat上编译,您需要将类路径包括tomcat\lib\servlet-api.jar或在GlassFish上:glassfish\lib\j2ee.jar

但两者都可以在两个平台上使用。您还需要在web.xml中设置您的servlet。


0
Chrome 91有一个新的变化,它支持在chrome 86-90和91+中使用。以下语法将实现这一点。
const fileHandle = await self.showSaveFilePicker({
   suggestedName: 'Untitled Text.txt',
   types: [{
      description: 'Text documents',
      accept: {
        'text/plain': ['.txt'],
      },
   }],
});

点击此处阅读更多:

https://developer.chrome.com/blog/new-in-chrome-91/

另一种解决方案是将其制作为 blob,然后使用 saveAs。

const blob = fetch("some-url-here").then(data => data.blob());
saveAs(blob, "filename.txt")

0
如果您的浏览器中有一个插件知道如何打开PDF文件,它将直接打开。就像图片和HTML内容一样。
因此,另一种方法是不在响应中发送MIME类型。这样,浏览器将永远不会知道应该打开哪个插件。因此,它将给您一个“保存/打开”对话框。

这很难实现,因为发送 MIME 类型的是服务器,当直接链接到 PDF 文件时,您无法更改标头。 - Karel Petranek

-2

使用大型PDF文件时,浏览器会挂起。

在Mozilla中,菜单工具选项应用程序,然后在内容类型Adobe Acrobat文档旁边。

在操作下拉菜单中,选择始终询问

这对我没有用,所以有效的方法是:

菜单工具* → 附加组件Adobe Acrobat(Firefox的Adobe PDF插件)→禁用。 现在我可以下载电子书了!


2
你看了问题吗?这不是一个跨浏览器的答案。 - Mark
1
@mark 这也是一些指令,用于提示用户强制下载PDF文件,而不是网站所有者。 - Nathan Hornby

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