(HTML) Pobierz plik PDF zamiast otwierać go w przeglądarce po kliknięciu


115

Zastanawiałem się, jak sprawić, by łącze do pliku PDF można było pobrać zamiast otwierać je w przeglądarce? Jak to się robi w html? (Zakładam, że jest to zrobione przez javascript lub coś w tym rodzaju).


3
Według mojej wiedzy jest to zachowanie, którego nie można skryptować. Większość przeglądarek ma własne ustawienia dotyczące zachowania podczas pobierania określonych typów plików.
Bart

1
Począwszy od HTML5, OP powinien zaktualizować poprawną odpowiedź na odpowiedź Sarima.
Omar Tariq


Na to pytanie również odpowiedziano tutaj: stackoverflow.com/a/30714824/847235
intrepidis

Odpowiedzi:


38

Nie możesz tego zrobić za pomocą HTML. To rozwiązanie serwerowe. Musisz przesyłać strumieniowo plik, aby przeglądarka wyzwoliła okno dialogowe zapisu.

Radziłbym tego nie robić. Sposób interakcji użytkownika z plikiem PDF należy pozostawić użytkownikowi.

AKTUALIZACJA (2014):

Więc ... ta odpowiedź wciąż spotyka się z wieloma negatywnymi opiniami. Zakładam, że po części odpowiedź na to pytanie udzielono 4 lata temu i jak wskazuje Sarim, istnieje teraz atrybut HTML 5,download który może to obsłużyć.

Zgadzam się i uważam, że odpowiedź Sarima jest dobra (prawdopodobnie powinna to być odpowiedź wybrana, jeśli OP kiedykolwiek powróci). Jednak ta odpowiedź jest nadal niezawodnym sposobem na poradzenie sobie z tym (jak wskazuje odpowiedź Yiğita Yenera i - co dziwne - ludzie się z nią zgadzają). Chociaż atrybut pobierania zyskał poparcie, nadal jest nierówny:

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


18
Wiem, że to ma rok - ale nie zgadzam się. Istnieją okoliczności, w których wymuszenie tego zachowania jest bardzo ważne dla przepływu aplikacji. Prawdziwą odpowiedzią jest ustawienie Dyspozycji treści w nagłówku na „załącznik” zamiast „w tekście”.
user158017

9
Zgadzam się, że w innych okolicznościach pozostawienie tego kontroli użytkownika jest lepsze. Jednak przyszedłem do tego wątku szukając odpowiedzi, a zaznaczona „odpowiedź” nie była odpowiedzią - to było „nie powinieneś tego robić”. Dla mnie to nie jest odpowiedź na pytanie. Zamiast tego podaj konkretna odpowiedź, a także doradztwo
user158017

1
Czasami pytanie jest błędne. ;) W każdym razie, jeśli chodzi o twój problem, to wszystko jest problemem UX. Zmuszanie sieci do określonego zachowania jest czasami konieczne, ale często istnieją lepsze rozwiązania z punktu widzenia UX. Moja odpowiedź jest również poprawna. Nie możesz zrobić tego, co chcesz zrobić z HTML (o to właśnie chodziło w pytaniu). To rozwiązanie po stronie serwera.
DA.

1
To jedna z moich najdziwniejszych odpowiedzi, jakie kiedykolwiek opublikowałem. Ludzie wciąż tu trafiają, aby go przegłosować. Co jest w porządku! Ale byłoby interesujące wiedzieć, dlaczego.
DA.

3
Jeśli chodzi o to odrzucanie głosów, może to oznaczać upadek cywilizacji, jak łatwo jest natknąć się na nieumyślnie aroganckiego tekstu. Ta odpowiedź uderza mnie tak długo w protekcjonalnej opinii i krótkich odpowiedziach. Zamiast akapitu 1, po prostu dodaj httpznacznik do pytania. Zamiast akapitu 2: „Możesz ponownie rozważyć, czy zapobieganie natychmiastowemu przeglądaniu plików PDF leży w najlepszym interesie wszystkich użytkowników. Powiedziawszy to ...” Następnie załóż, że OP i przyszli czytelnicy są dorośli i przejdź do odpowiedzi, na przykład Yenera .
Bob Stein

133

Dzięki html5 jest to teraz możliwe. Ustaw atrybut „download” w elemencie.

<a href="http://link/to/file" download="FileName">Download it!</a>

Źródło: http://updates.html5rocks.com/2011/08/Downloading-resources-in-HTML5-a-download


Lepiej wybierz to rozwiązanie, jeśli jest obsługiwane. Oto sposób, aby sprawdzić, czy tak jestif ("download" in document.createElement("a")){ ... }
pmrotule

Dodałem kolejną odpowiedź poniżej (chociaż zły hack), chociaż jest to nadal preferowany sposób, być może sposób hackowania może być oferowany w przypadku nieobsługiwanych przeglądarek.
Sarim,

Czy istnieje sposób, aby określić tekst pliku PDF zamiast wspominać o ścieżce do pliku? Potrzebuję utworzyć pdf z div html, ale nie chcę otwierać kolejnego okna, pobieranie powinno wyglądać tak, jak w tej odpowiedzi ..
T.Adak

1
Obecnie w sierpniu 2019 r. Obsługa przeglądarek wydaje się być ulepszona dla tej funkcji, patrz: w3schools.com/tags/att_a_download.asp
Daniel Resch

2
Należy pamiętać, że atrybut pobierania jest obsługiwany tylko w przypadku żądań tego samego pochodzenia.
Quentin

82

Jest to możliwe tylko po ustawieniu nagłówka odpowiedzi http za pomocą kodu po stronie serwera. Mianowicie;

Content-Disposition: attachment; filename=fname.ext

2
to jest doskonała odpowiedź - po prostu znajdź sposób, aby to zrobić w odpowiednim języku po stronie serwera.
user158017

Przykład Apache . Przykład kolby .
Bob Stein

Niestety iOS nadal będzie wyświetlać podgląd i nie pobierać plików PDF, nawet jeśli dyspozycja treści to „załącznik”.
Jorn van de Beek

14

Musisz zmienić wysłane nagłówki http. W zależności od serwera możesz zmodyfikować swój .htaccess w następujący sposób:

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

Nie ma potrzeby kłamać na temat rodzaju treści. Ustawienie dyspozycji treści jest wystarczające.
Quentin

9

będziesz musiał użyć skryptu PHP (lub innego języka do tego celu po stronie serwera)

<?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');
?>

i użyj httacces do przekierowania (przepisania) do pliku PHP zamiast do pliku PDF


Hmm, działa świetnie, gdy otwieram plik php bezpośrednio. Ale kiedy próbuję użyć przekierowania, jak tutaj: Redirect 301 /_PDFs/Catalogue.pdf http://www.example.com/_PDFs/___download_the_catalogue_instead_opening.phpi próbuję otworzyć plik pdf, nadal otwiera oryginał w przeglądarce, zamiast tego pobiera wersję o zmienionej nazwie ...
ellockie

AKTUALIZACJA: Działa, gdy nie ma pliku, który jest bezpośrednio wywoływany (jako „Catalogue.pdf” w moim przykładzie). Wtedy przekierowanie działa idealnie. Dzięki!
ellockie

8

Możesz użyć

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

Sprawdź ten przykład:

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

Dotyczy to ASP.NET. Jestem pewien, że możesz znaleźć podobne rozwiązania we wszystkich innych językach po stronie serwera. Jednak o ile wiem, nie ma rozwiązania javascript.


to jest odpowiedź (podobnie jak powiązana z PHP). chodzi o to, że trzeba edytować nagłówek odpowiedzi http.
user158017

5

Bez atrybutu html5 można to osiągnąć za pomocą php:

Utwórz plik php o nazwie download.php z tym kodem:

<?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();
}

Teraz, jeśli chcesz automatycznie rozpocząć pobieranie pliku PDF, napisz ten javascript:

<script>window.location = "download.php";</script>

Jeśli chcesz, aby to działało na łączu, użyj tego ...

<a href='javascript:window.location = "download.php"'>
    Download it!
</a>

4
Tylko ostrzeżenie, że musisz być ostrożny, robiąc to z parametrami adresu URL. Na przykład $file = $_GET['$file'];. Ponieważ można by było wtedy również zadzwonić download.php?file=../../../wp-config.phplub jakikolwiek inny dany zasób. Dodatkowe sprawdzanie rozszerzeń, typów MIME i dozwolonych ścieżek pobierania z (oraz usuwanie rzeczy takich jak "../") jest bardzo ważne!
Giel Berkers

czy to ja, czy zrobienie <a href='javascript...'> jest dokładnie tym samym, co umieszczenie bezpośredniego linku w<a href='download.php'> ?
allan.simon.

5

Jeśli chcesz bezpośrednio pobrać dowolny obraz lub plik pdf z przeglądarki zamiast otwierać go w nowej karcie, to w javascript należy ustawić wartość na pobranie atrybutu tworzenia dynamicznego łącza

    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);

W przypadku nowej aktualizacji Chrome czasami zdarzenie nie działa. do tego zostanie użyty następujący kod

  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);

Dołączanie elementu podrzędnego i usuwanie elementu podrzędnego jest przydatne tylko w przypadku Firefoksa, przeglądarki Internet Explorer. Na Chrome będzie działać bez dołączania i usuwania dziecka


2

Najlepszym rozwiązaniem dla mnie było to, które napisał Nick na swoim blogu

Podstawową ideą jego rozwiązania jest użycie modów nagłówkowych serwerów Apache i edycja pliku .htaccess, tak aby zawierała dyrektywę FileMatch, która wymusza działanie wszystkich plików * .pdf jako strumienia zamiast załącznika. Chociaż w rzeczywistości nie wymaga to edycji HTML (jak w oryginalnym pytaniu), nie wymaga żadnego programowania jako takiego.

Pierwszym powodem, dla którego wolałem podejście Nicka, jest to, że pozwoliło mi to ustawić je dla poszczególnych folderów, aby pliki PDF w jednym folderze mogły być nadal otwierane w przeglądarce, podczas gdy inne (te, które chcielibyśmy, aby użytkownicy mogli edytować, a następnie ponownie przesłać) być zmuszane jako pliki do pobrania.

Chciałbym również dodać, że w przypadku plików PDF istnieje opcja wysyłania / wysyłania formularzy do wypełnienia za pośrednictwem interfejsu API na serwery, ale implementacja zajmuje trochę czasu.

Drugim powodem było to, że liczy się czas. Napisanie procedury obsługi plików PHP w celu wymuszenia dyspozycji zawartości w nagłówku () również zajmie mniej czasu niż API, ale nadal będzie dłuższe niż podejście Nicka.

Jeśli wiesz, jak włączyć mod Apache i edytować pliki .htaccss, możesz to uzyskać w około 10 minut. Wymaga hostingu Linux (nie Windows). To może nie być odpowiednie podejście do wszystkich zastosowań, ponieważ wymaga dostępu do serwera wysokiego poziomu do konfiguracji. W związku z tym, jeśli powiedziałeś o dostępie, prawdopodobnie dlatego, że wiesz już, jak zrobić te dwie rzeczy. Jeśli nie, sprawdź blog Nicka, aby uzyskać więcej instrukcji.


2

Ponieważ sposób html5 (moja poprzednia odpowiedź) nie jest dostępny we wszystkich przeglądarkach, oto inny nieco hackowy sposób.

To rozwiązanie wymaga udostępniania zamierzonego pliku z tej samej domeny LUB posiadania uprawnienia CORS.

  1. Najpierw pobierz zawartość pliku przez XMLHttpRequest (Ajax).
  2. Następnie utwórz identyfikator URI danych przez kodowanie base64 zawartości pliku i ustaw typ nośnika na application/octet-stream. Wynik powinien wyglądać

data:application/octet-stream;base64,SGVsbG8sIFdvcmxkIQ%3D%3D

Teraz gotowe location.href = data. Spowoduje to pobranie pliku przez przeglądarkę. Niestety nie możesz w ten sposób ustawić nazwy pliku ani rozszerzenia. Majstrowanie przy mediach może coś przynieść.

Zobacz szczegóły: https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs



1

Jeśli używasz HTML5 (i myślę, że teraz wszyscy go używają), istnieje atrybut o nazwie download.

dawny. <a href="somepathto.pdf" download="filename">

tutaj filenamejest opcjonalne, ale jeśli zostanie podane, przyjmie tę nazwę dla pobranego pliku.


Niestety, muszę przyznać, że jestem zbyt głupi, żeby zrozumieć ten tag. Piszę to: <a href="download/Curriculum_it.pdf.zip">Download curriculum</a>lub tamto: <a href="download/Curriculum_it.pdf.zip" download="Curriculum_it">Download curriculum</a>i nie widzę absolutnie żadnej różnicy w tym, jak to działa. Oba pobierają plik .zip. A w drugim użycie opcji filename wydaje się nic nie robić.
Garavani

0

Zachowanie powinno zależeć od tego, jak przeglądarka jest skonfigurowana do obsługi różnych typów MIME. W tym przypadku typ MIME to application / pdf. Jeśli chcesz zmusić przeglądarkę do pobrania pliku, możesz spróbować wymusić inny typ MIME na plikach PDF. Odradzam to, ponieważ użytkownik powinien wybrać, co się stanie, gdy otworzą plik PDF.



-1

Wreszcie znalazłem ...... utwórz dynamiczny tag kotwicy i kliknij go

<script> 
   $('#myclick').click(function(){
       $('body').append('<a id="link" href="mypdf.pdf" 
        download="Payment.pdf">&nbsp;</a>');
       $('#link')[0].click();
   });
</script>

„Payment.pdf” dotyczy tylko nazwy niestandardowej.


Nie ma potrzeby dynamicznego generowania łącza.
Quentin

Należy pamiętać, że atrybut pobierania jest obsługiwany tylko w przypadku żądań tego samego pochodzenia.
Quentin

Wydaje się, że jest to ta sama odpowiedź, co ta sprzed trzech lat.
Quentin
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.