(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).

404Error
źródło
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

DA.
źródło
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

Sarim
źródło
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
Yiğit Yener
źródło
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>
facet php
źródło
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

beardhatcode
źródło
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.

mihsathe
źródło
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>
hlozancic
źródło
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

Prasad Joshi
źródło
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.

Strixy
źródło
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

Sarim
źródło
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.

Akshay
źródło
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.

Aleksi Yrttiaho
źródło
0

Możesz użyć download.js ( https://github.com/rndme/download i http://danml.com/download.html ). Jeśli plik znajduje się w zewnętrznym adresie URL, musisz wysłać żądanie Ajax, ale jeśli tak nie jest, możesz użyć funkcji:

download(Path, name, mime)

Przeczytaj ich dokumentację, aby uzyskać więcej informacji w GitHub.

Wisznu S.
źródło
To najlepsze rozwiązanie javascript do pobierania w innej domenie.
Edhowler
-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.

Pushpender Singh
źródło
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