Принудительно открывать всплывающее окно «Сохранить как…», открывать по текстовой ссылке, щелкнуть PDF в HTML


173

У меня есть несколько больших каталогов PDF на моем веб-сайте, и мне нужно связать их по мере загрузки. Когда я гуглил, я обнаружил такую ​​вещь, отмеченную ниже. Он должен открыть всплывающее окно « Сохранить как ... » по ссылке нажмите ...

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

Но это не работает: / Когда я ссылаюсь на файл, как показано ниже, он просто ссылается на файл и пытается открыть файл.

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

ОБНОВЛЕНИЕ (согласно ответам ниже):

Как я вижу, для этого не существует 100% надежного кросс-браузерного решения. Вероятно, лучшим способом является использование одного из веб-сервисов, перечисленных ниже, и предоставление ссылки для скачивания ...


1
не используйте mimetype для файлов PDF.
бхупс

Я попробовал ваше обновленное решение, artmania, но возникла та же проблема, что и у меня в Safari. Я получаю то, что выглядит как PDF, в окне браузера, и только когда я нажимаю на вкладки «предварительный просмотр» или «скачать» внизу, я получаю функцию поиска, которая мне так необходима.
Пустоши


похожий, но менее специфичный для типа файла: stackoverflow.com/questions/1465573/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Ответы:


268

17
На момент написания этого комментария downloadатрибут ограничен Chrome, Firefox и Opera. Даже последние версии IE и Safari не поддерживают его. Для дальнейшей поддержки: проверьте caniuse.com/#feat=download !
Сигморал

Проверка ошибок NetBeans жалуется на это, но, кажется, работает нормально. Вы можете указать предварительное имя для нового файла, например, так: download = "myFile.txt"
Yster

1
Это работает в Edge на момент написания этого комментария и кажется единственным возможным способом остановить открытие гиперссылок PDF-файлов при очень плохой попытке Edge просмотреть PDF-файл.

На момент написания этого комментария я тестировал его на Chrome, Opera, Edge, Mozilla. Все последние. Работает на всех, кроме Mozilla.
SI

7
Это работает только для ссылок того же источника, как упомянуто на caniuse.com/#feat=download . Если ваши ссылки имеют перекрестное происхождение, единственным вариантом (на данный момент) является принудительный выбор типа ответа «application / octet-stream», как предлагают многие ответы. Если у вас нет доступа к серверу, вы можете попробовать прокси и настроить заголовок ответа вручную.
Жан-Креститель

81
<a href="file link" download target="_blank">Click here to download</a>

Это работает для меня в Firefox и Chrome.


2
Это точно так же, как текущий топ-ответ от Аюша Гупты в 2013 году. Тем target="_blank"не менее, он может сделать его несколько более удобным для не поддерживающих браузеров (PDF-файлы затем открываются в новом окне / вкладке, а не перезаписывают текущую страницу).
Сигморал

3
Для меня target="_blank"было необходимо, так как downloadтолько не удалось правильно запустить загрузку (Chrome)
casraf

2
Если вы дадите строку в downloadатрибуте, она будет использоваться как имя файла. Я использую его в пользовательских скриптах все время.
Слабое время

34

Мета-теги не являются надежным способом достижения этого результата. Как правило, вы даже не должны этого делать - пользователь / пользовательский агент должен решать, что делать с контентом, который вы предоставляете. Пользователь всегда может заставить свой браузер загрузить файл, если он этого хочет.

Если вы все еще хотите заставить браузер загрузить файл, измените заголовки HTTP напрямую. Вот пример кода PHP:

$path = "path/to/file.pdf";
$filename = "file.pdf";
header('Content-Transfer-Encoding: binary');  // For Gecko browsers mainly
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($path)) . ' GMT');
header('Accept-Ranges: bytes');  // Allow support for download resume
header('Content-Length: ' . filesize($path));  // File size
header('Content-Encoding: none');
header('Content-Type: application/pdf');  // Change the mime type if the file is not PDF
header('Content-Disposition: attachment; filename=' . $filename);  // Make the browser display the Save As dialog
readfile($path);  // This is necessary in order to get it to actually download the file, otherwise it will be 0Kb

Обратите внимание, что это всего лишь расширение протокола HTTP; некоторые браузеры могут игнорировать это в любом случае.


4
На практике я считаю, что это широко реализовано.
Мэтью Уилсон,

Это лучшее решение, без проблем и работает. Вы можете напрямую загрузить любой тип файла, используя этот метод. +1
casraf

3
Content-Transfer-Encoding не существует в HTTP. Content-Encoding: ни один не является бесполезным.
Джулиан Решке

ЗАМЕТЬТЕ в своем ответе, что ЕСЛИ файл с внешнего сервера / домена, то этот ответ может не быть решением ...
T.Todua

Я хотел бы добавить, что у меня был сбой этого или аналогичного кода на некоторых серверах, когда файлы становятся большими (> 80 МБ в моем случае). Использование ob_end_flush()тоже не помогло.
Хендрик

22

У меня была такая же проблема, и я нашел решение, которое до сих пор прекрасно работало. Вы помещаете следующий код в свой .htaccessфайл:

<FilesMatch "\.(?i:pdf)$">
  ForceType application/octet-stream
  Header set Content-Disposition attachment
</FilesMatch>

Он пришел из « Принудительно загрузить файл вместо того, чтобы отображаться в браузере» .


4
Это работало хорошо, так как у меня был определенный каталог документов для скачивания. Я опустил ForceType, чтобы типы оставались как есть. Мне также не нужен регистронезависимый; мой, кажется, уже без учета регистра. Я добавил пару дополнительных типов, в том числе option-x для старых / новых расширений Office:<FilesMatch "\.(pdf|xlsx?|docx?)$">
goodeye

Это прекрасно работает даже в OSX Safari, где другие ответы (включая принятый, как указал один комментатор) ограничены определенными браузерами, которые поддерживают данную функцию HTML. Этот вариант кажется мне более идеальным, поскольку он работал по всем направлениям, хотя для него требуется доступ более высокого уровня к файлам конфигурации сервера.
Брайт

Вы также можете поместить это прямо в файл apache.conf, я не использую .htaccess, так как он требует больше ресурсов.
Майкл Лихорадка

Как веб-сайт на базе Windows реализует это, поскольку они не могут читать файлы htaccess?
PoloHoleSet

10

Я нашел очень простое решение для Firefox (работает только с относительным, а не с прямым href): add type="application/octet-stream":

<a href="./file.pdf" id='example' type="application/octet-stream">Example</a>

1
@Martin Chrome для Chrome OS и Firefox для Linux. Оказывается, файл должен быть локальным, чтобы он работал. Моя ссылка была ссылкой на облачное хранилище.
ttfreeman

7

Попробуйте добавить эту строку в ваш файл .htaccess.

AddType application/octet-stream .pdf

Я надеюсь, что он будет работать, так как он не зависит от браузера.


Мне было бы интересно узнать, почему это было понижено - это один из самых простых методов и работ: css-tricks.com/snippets/htaccess/…
Натан Хорнби

Люди пытаются изменить базовую функциональность сервера на бесплатных хостинг-сайтах, а затем понижают голос, потому что не могут заставить его работать. Любое другое решение будет иметь предостережения, потому что это «взлом», чтобы заменить это.
Заброшенная корзина

Я не одобряю это, потому что это неправильное решение проблемы. Это плохая идея возиться с типами ресурсов.
Брэд

@NathanHornby - я не отрицал это, но это не сработало бы для любого размещенного на Windows сайта, так как они не используют .htaccess.
PoloHoleSet

Я не понизил голос, но это решение слепо влияет на ВСЕ файлы этого суффикса. Это неизбирательно и поэтому не будет уместным во всех случаях.
JBH

6

Обычно это происходит, потому что некоторые настройки браузера или плагины напрямую открывают PDF в том же окне, как простая веб-страница.

Следующее может помочь вам. Я сделал это на PHP несколько лет назад. Но в настоящее время я не работаю на этой платформе.

<?php
    if (isset($_GET['file'])) {
        $file = $_GET['file'];
        if (file_exists($file) && is_readable($file) && preg_match('/\.pdf$/',$file)) {
            header('Content-type: application/pdf');
            header("Content-Disposition: attachment; filename=\"$file\"");
            readfile($file);
        }
    }
    else {
        header("HTTP/1.0 404 Not Found");
        echo "<h1>Error 404: File Not Found: <br /><em>$file</em></h1>";
    }
?>

Сохраните выше как download.php .

Сохраните этот небольшой фрагмент в виде файла PHP где-нибудь на вашем сервере, и вы можете использовать его для загрузки файла в браузере, а не для непосредственного отображения. Если вы хотите обслуживать файлы, отличные от PDF, удалите или измените строку 5.

Вы можете использовать это так:

Добавьте следующую ссылку в ваш HTML-файл.

<a href="download.php?file=my_pdf_file.pdf">Download the cool PDF.</a>

Ссылка от: Этот блог


7
Похоже, это хороший способ подать каждый файл на вашем сервере всем, кто обращает на это внимание. download.php?file=database_password_file.phpнапример.
pbarney

5

Просто поместите следующий код в ваш .htaccessфайл:

AddType application/octet-stream .csv
AddType application/octet-stream .xls
AddType application/octet-stream .doc
AddType application/octet-stream .avi
AddType application/octet-stream .mpg
AddType application/octet-stream .mov
AddType application/octet-stream .pdf

Или вы также можете сделать трюк с помощью JavaScript

element.setAttribute( 'download', whatever_string_you_want);

1
Разве это не предполагает, что веб-сервер Apache ?
Питер Мортенсен

5

Я просто использовал это, но я не знаю, работает ли он во всех браузерах.

Это работает в Firefox:

<a href="myfile.pdf" download>Click to Download</a>

1
Это предлагается, и с дополнительной справочной информацией, в более раннем ответе .
usr2564301

4

Очень простой способ для достижения этой цели, без использования внешних сайтов для загрузки или изменения заголовков и т.д., чтобы просто создать ZIP - файл с PDF внутри и ссылки непосредственно в файл ZIP. Это ВСЕГДА вызовет диалоговое окно «Сохранить / Открыть», и людям все еще будет легко дважды щелкнуть окна PDF, когда запущена программа, связанная с .zip.

Кстати, отличный вопрос, я тоже искал ответ, так как большинству встроенных в браузер плагинов PDF требуется слишком много времени, чтобы отобразить что-либо (и часто зависает браузер во время загрузки PDF).


31
Страшное удобство использования. Многие конечные пользователи не знают, что делать с zip-файлами.
CodeWarrior

1
Иногда простые решения - лучшие решения!
Эльрадо

1
Не очень хорошее решение. У меня есть именно эта проблема с Firefox и файлом ZIP. Что я должен делать? ZIP файл? В этом случае изменение заголовков HTTP может быть решением, но у меня нет доступа к этому.
Арно Вейль

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

Очень простой способ сделать это, если вам нужно принудительно загрузить отдельную ссылку на вашей странице, - это использовать атрибут загрузки HTML5 в href-ссылке.

Смотрите: http://davidwalsh.name/download-attribute

при этом вы можете переименовать файл, который будет загружать пользователь, и в то же время принудительно загружать его.

Были споры о том, является ли это хорошей практикой или нет, но в моем случае у меня есть встроенный просмотрщик для PDF-файла, и просмотрщик не предлагает ссылку для скачивания, поэтому я должен предоставить ее отдельно. Здесь я хочу убедиться, что пользователь не открывает PDF-файл в веб-браузере, что может привести к путанице.

В этом нет необходимости открывать диалоговое окно «Сохранить как», но ссылка будет загружена прямо в заданный пункт назначения загрузки. И, конечно, если вы делаете сайт для кого-то другого, и вам нужно, чтобы он вручную вводил атрибуты в свои ссылки, это, вероятно, плохая идея, но если есть способ добавить атрибут в ссылки, это может быть легким решением.


1

Это старый пост, но вот мое решение в 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внутри вашего <a>тега, и вы автоматически загрузите его. Вы также можете добавить его к родителю divи получить все ссылки внутри него.

Пример:

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

Это отлично подходит для WordPress и любых других систем или пользовательских сайтов.


0

После имени файла в HTML-код добавляю ?forcedownload=1

Для меня это был самый простой способ вызвать диалоговое окно для сохранения или загрузки.


0

Если в браузере есть плагин, который знает, как открыть файл PDF, он откроется напрямую. Как в случае изображений и HTML-контента.

Таким образом, альтернативный подход - не отправлять ваш MIME-тип в ответе. Таким образом, браузер никогда не узнает, какой плагин должен его открыть. Следовательно, это даст вам диалоговое окно Сохранить / Открыть .


Этого трудно достичь, потому что именно сервер отправляет mime-тип, и при прямой ссылке на файл PDF вы не можете изменить заголовки.
Карел Петранек

0

У меня была очень похожая проблема с добавленной проблемой, которая требовалась для создания ссылок на скачивание файлов внутри ZIP-файла.

Сначала я попытался создать временный файл, затем предоставил ссылку на временный файл, но обнаружил, что некоторые браузеры просто отображают содержимое (файл CSV Excel), а не предлагают его для загрузки. В конце концов я нашел решение с помощью сервлета. Он работает как на Tomcat, так и на GlassFish, и я попробовал это сделать в Internet Explorer 10 и Chrome.

Сервлет принимает в качестве входных данных полный путь к ZIP-файлу и имя файла внутри ZIP-файла, который необходимо загрузить.

Внутри моего JSP-файла у меня есть таблица, отображающая все файлы внутри zip-файла со ссылками: onclick='download?zip=<%=zip%>&csv=<%=csv%>'

Код сервлета находится в 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 вам нужно, чтобы classpath включал tomcat \ lib \ servlet-api.jar или GlassFish: glassfish \ lib \ j2ee.jar

Но любой из них будет работать на обоих. Вы также должны установить свой сервлет web.xml.


0

Добавить заголовок ответа Content-Disposition: attachment; сопровождаемый именем файла. Удалите мета-содержимое-расположение; который откроет документ в том же окне

В Java это установлено как

response.setHeader("Content-Disposition", "attachment;filename=test.jpg");

-2

С большими файлами PDF браузер зависает. В Mozilla выберите СервисПараметрыПриложения , затем рядом с типом содержимого документ Adobe Acrobat. В раскрывающемся списке «Действие» выберите « Всегда спрашивать» .

Это не сработало для меня, так что сработало:

Инструменты меню * → ДополненияAdobe Acrobat (плагин Adobe PDF для Firefox) → ОТКЛЮЧИТЬ. Теперь я могу скачивать электронные книги!


2
ты прочитал вопрос? это не кросс-браузерный ответ
Марк

1
@ mark - это также инструкция для пользователя, который запрашивает принудительную загрузку PDF-файлов, а не для владельца веб-сайта.
Натан Хорнби
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.