Примушуйте відкривати спливаюче вікно "Зберегти як ...", відкривши текстове посилання, натисніть на 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 у вікні браузера, і лише після натискання вкладки «попередній перегляд» або «завантаження» внизу я отримую функцію пошуку, яка мені так відчайдушно потрібна.
heathwaller


Схоже , але менш тип файлу конкретні: stackoverflow.com/questions/1465573 / ...
Чіро Сантіллі郝海东冠状病六四事件法轮功

Відповіді:


267

З відповіді на примушувати браузер зберігати файл як після натискання посилання :

<a href="path/to/file" download>Click here to download</a>

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

Перевірка помилок Netbeans скаржиться на це, але, здається, працює добре. Ви можете вказати попереднє ім'я для нового файлу, наприклад: download = "myFile.txt"
Yster,

1
Це працює в Edge на момент написання цього коментаря, і здається єдиним можливим способом зупинити відкриття гіперпосилання PDF-файлів у дуже поганій спробі Edge для перегляду PDF.

На час цього коментаря я тестував його на Chrome, Opera, Edge, Mozilla. Усі останні. Працює над усіма, крім Mozilla.
СІ

7
Це працює лише для посилань з однаковим походженням, про що згадується на сайті caniuse.com/#feat=download . Якщо ваші посилання є перехресним походженням, ваш єдиний варіант (поки що) - змусити тип відповіді на "application / octet-stream", як підказує багато відповідей. Якщо у вас немає доступу до сервера, ви можете спробувати проксі і встановити заголовок відповіді вручну.
джин-батист

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

Для мене це працює у Firefox та Chrome.


2
Це точно так само, як у поточній верхній відповіді від Ayush Gupta в 2013 році. Це target="_blank"може зробити його трохи більш корисним для не підтримуючих браузерів (PDF-файли потім відкриваються в новому вікні / вкладці, а не перезаписують поточну сторінку).
Sygmoral

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
касраф

3
Content-Transfer-Encoding не існує в HTTP. Кодування вмісту: жоден не є марним.
Джуліан Решке

Зробіть ПРИМІТКА у своїй відповіді, що ІЧ-файл із зовнішнього сервера / домену, то ця відповідь може не вирішити ...
T.Todua,

Я хотів би додати, що у мене цей або подібний код вийшов з ладу на певних серверах, коли файли набувають великих розмірів (> 80 Мб у моєму випадку). Використання ob_end_flush()також не допомогло.
Гендрик

22

У мене було це саме питання, і я знайшов рішення, яке до цього часу чудово працювало. Ви поміщаєте такий .htaccessфайл у свій файл:

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

Він прийшов із програми «Завантажити файл», а не відображатися в браузері .


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

Це чудово спрацювало навіть в OSX Safari, де інші відповіді (включаючи прийняті, як вказував один коментатор) обмежуються певними браузерами, які підтримують дану функцію HTML. Мені це здається більш ідеальним, оскільки він працював у всьому світі, хоча він вимагає доступу більш високого рівня до файлів конфігурації сервера.
bwright

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

Як веб-сайт, розміщений під керуванням Windows, реалізує це, оскільки вони не можуть читати файли htaccess?
PoloHoleSet

9

Я знайшов дуже просте рішення для Firefox (працює лише з відносним, а не з прямим href): add type="application/octet-stream":

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

1
@Martin Chrome в ОС Chrome і Firefox в Linux. Виявляється, файл повинен бути локальним, щоб він міг працювати. Мій href був URL-адресою хмарного сховища.
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 ?
Пітер Мортенсен


4

дійсно простий спосіб для досягнення цієї мети, без використання зовнішніх сайтів для завантаження або зміни заголовків і т.д., щоб просто створити ZIP - файл з PDF всередині і посилання безпосередньо в файл ZIP. Це ЗАВЖДИ запустить діалогове вікно "Зберегти / відкрити", і людям все ще легко двічі клацнути вікна PDF, запускається програма, пов'язана з .zip.

До речі, велике запитання, я також шукав відповідь, оскільки для більшості плагінів PDF, вбудованих у браузер, потрібна стільки часу, щоб відображати що-небудь (і часто буде вішати браузер під час завантаження PDF).


31
Страшна юзабіліті. Багато кінцевих користувачів не знають, що робити з поштовим файлом.
CodeWarrior

1
Іноді прості солюціони - найкращі рішення!
Ельрадо

1
Не вдале рішення. У мене саме така проблема з Firefox та ZIP-файлом. Що я повинен зробити? ZIP файл? У цьому випадку зміна заголовків HTTP може бути рішенням, але я не маю доступу до цього.
Арно Вейл

2

Рішення на стороні сервера є більш сумісним, доки атрибут "завантажити" не буде реалізований у всіх браузерах.

Одним із прикладів 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%>'

Код сервлета знаходиться у завантаженні.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.


0

Додати заголовок відповіді Content-Disposition: вкладення; слідом за ім'ям файлу. Видаліть мета-диспозицію; Inline; який відкриє документ у тому ж вікні

У 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.