(HTML) Tải xuống tệp PDF thay vì mở chúng trong trình duyệt khi được nhấp


115

Tôi tự hỏi làm thế nào để tạo một liên kết tệp PDF có thể tải xuống thay vì mở chúng trong trình duyệt? Làm thế nào điều này được thực hiện trong html? (Tôi cho rằng nó được thực hiện thông qua javascript hoặc thứ gì đó).


3
Đây là hành vi của tôi không phải là kịch bản. Hầu hết các trình duyệt sẽ có cài đặt riêng cho hành vi phải làm gì với các loại tệp cụ thể khi tải xuống.
Bart

1
Đối với HTML5, OP nên cập nhật câu trả lời chính xác cho câu trả lời của Sarim.
Omar Tariq,


Câu hỏi này cũng đã được trả lời tại đây: stackoverflow.com/a/30714824/847235
intrepidis

Câu trả lời:


38

Bạn không thể làm điều này với HTML. Đó là một giải pháp dựa trên máy chủ. Bạn phải truyền tệp để trình duyệt kích hoạt hộp thoại lưu.

Tôi khuyên bạn không nên làm điều này. Cách người dùng tương tác với PDF sẽ do người dùng quyết định.

CẬP NHẬT (2014):

Vì vậy, ... câu trả lời này vẫn nhận được nhiều phản đối. Tôi giả sử một phần của điều đó là điều này đã được trả lời 4 năm trước và như Sarim đã chỉ ra, bây giờ có thuộc tính HTML 5download có thể xử lý điều này.

Tôi đồng ý, và nghĩ câu trả lời của Sarim là tốt (có lẽ nó sẽ là câu trả lời được chọn nếu OP quay trở lại). Tuy nhiên, câu trả lời này vẫn là cách đáng tin cậy để xử lý nó (như câu trả lời của Yiğit Yener đã chỉ ra và - kỳ lạ thay - mọi người đồng ý). Mặc dù thuộc tính tải xuống đã được hỗ trợ, nhưng nó vẫn còn nguyên vẹn:

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


18
Tôi biết đây là một năm cũ - nhưng tôi không đồng ý. Có những trường hợp buộc hành vi này là rất quan trọng đối với luồng ứng dụng. Câu trả lời thực tế là đặt nội dung-Bố trí trong tiêu đề là "tệp đính kèm" thay vì "nội dòng".
user158017

9
Tôi đồng ý rằng trong các trường hợp khác, để quyền kiểm soát của người dùng sẽ tốt hơn. Tuy nhiên, tôi đến chủ đề này để tìm kiếm câu trả lời và "câu trả lời" được chọn không phải là câu trả lời - đó là "bạn không nên làm như vậy". Đối với tôi, đó không phải là câu trả lời cho câu hỏi. Thay vào đó, hãy đưa ra một câu trả lời cụ thể câu trả lời và cũng tư vấn cho.
user158017

1
Đôi khi câu hỏi là sai. ;) Dù sao đi nữa, về vấn đề của bạn, đó là tất cả vấn đề của người dùng. Việc buộc web hoạt động theo những cách cụ thể đôi khi là cần thiết, nhưng thường có các giải pháp tốt hơn từ góc độ người dùng. Ngoài ra, câu trả lời của tôi là đúng. Bạn không thể làm những gì bạn muốn làm với HTML (đó là những gì câu hỏi được đặt ra). Đó là giải pháp phía máy chủ.
ĐA.

1
Đây là một trong những câu trả lời kỳ lạ nhất của tôi từng được đăng. Mọi người vẫn tìm đến đây để phản đối nó. Cái nào tốt! Nhưng sẽ rất thú vị nếu biết tại sao.
ĐA.

3
Về sự phản đối đó, có thể là sự sụp đổ của nền văn minh mà người ta dễ dàng bắt gặp sự kiêu ngạo vô tình trong văn bản. Câu trả lời này gây ấn tượng với tôi miễn là ý kiến ​​bảo trợ và câu trả lời ngắn gọn. Thay vì đoạn 1, chỉ cần thêm httpthẻ vào câu hỏi. Thay vì đoạn 2: "Bạn có thể muốn xem xét lại việc ngăn chặn xem PDF ngay lập tức có phải là lợi ích tốt nhất của tất cả người dùng hay không. Đã nói rằng ..." Sau đó, giả sử OP và người đọc tương lai là người lớn và chuyển sang một câu trả lời có thể hành động như Yener .
Bob Stein

133

Với html5, bây giờ có thể. Đặt một phần tử "tải xuống".

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

Nguồn: http://updates.html5rocks.com/2011/08/Downloading-resources-in-HTML5-a-download


Tốt hơn bạn nên sử dụng giải pháp này nếu nó được hỗ trợ. Đây là một cách để kiểm tra xem nó có phải khôngif ("download" in document.createElement("a")){ ... }
pmrotule

Tôi đã thêm một câu trả lời khác bên dưới (mặc dù là hack xấu), trong khi đây vẫn là cách được ưa thích, có lẽ cách hack có thể được cung cấp cho các trình duyệt không được hỗ trợ.
Sarim

Có cách nào để chỉ định văn bản cho pdf thay vì đề cập đến đường dẫn tệp không? Tôi cần phải tạo pdf từ một div html nhưng tôi không có nhu cầu mở một cửa sổ khác, tải nên seemless như trong câu trả lời này ..
T.Adak

1
Kể từ bây giờ vào tháng 8 năm 2019, hỗ trợ Trình duyệt dường như đã được tăng cường cho tính năng này, hãy xem: w3schools.com/tags/att_a_download.asp
Daniel Resch

2
Lưu ý rằng thuộc tính tải xuống chỉ được hỗ trợ cho các yêu cầu cùng nguồn gốc.
Quentin

82

Điều này chỉ có thể thực hiện được khi đặt tiêu đề phản hồi http bằng mã phía máy chủ. Cụ thể là;

Content-Disposition: attachment; filename=fname.ext

2
đây là câu trả lời hoàn hảo - chỉ cần tìm cách thực hiện điều đó bằng ngôn ngữ phía máy chủ thích hợp.
user158017

Ví dụ về Apache . Flask ví dụ.
Bob Stein

Rất tiếc, iOS sẽ vẫn xem trước và không tải xuống tệp pdf ngay cả khi bố cục nội dung là 'tệp đính kèm'.
Jorn van de Beek

14

Bạn cần thay đổi các tiêu đề http đã gửi. Tùy thuộc vào máy chủ của bạn, bạn có thể sửa đổi .htaccess của mình như sau:

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

Không cần phải nói dối về loại nội dung. Thiết lập bố cục nội dung là đủ.
Quentin

9

bạn sẽ cần sử dụng tập lệnh PHP (hoặc một ngôn ngữ phía máy chủ khác cho việc này)

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

và sử dụng httacces để chuyển hướng (viết lại) đến tệp PHP thay vì pdf


Hmm, nó hoạt động tuyệt vời khi tôi mở trực tiếp tệp php. Nhưng khi tôi cố gắng sử dụng chuyển hướng, như ở đây: Redirect 301 /_PDFs/Catalogue.pdf http://www.example.com/_PDFs/___download_the_catalogue_instead_opening.phpvà cố gắng mở file pdf, nó vẫn mở ra ban đầu trong trình duyệt, thay vì tải về các phiên bản đổi tên ...
ellockie

CẬP NHẬT: Nó hoạt động khi không có tệp nào đang được gọi trực tiếp (như "Catalogue.pdf" trong ví dụ của tôi). Sau đó, chuyển hướng hoạt động hoàn hảo. Cảm ơn!
ellockie,

8

Bạn có thể dùng

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

Kiểm tra ví dụ này:

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

Điều này áp dụng cho ASP.NET. Tôi chắc chắn rằng bạn có thể tìm thấy các giải pháp tương tự trong tất cả các ngôn ngữ phía máy chủ khác. Tuy nhiên, không có giải pháp javascript nào theo hiểu biết tốt nhất của tôi.


đây là câu trả lời (cũng như câu trả lời liên quan cho PHP). vấn đề là tiêu đề phản hồi http phải được chỉnh sửa.
user158017

5

Nếu không có thuộc tính html5, người ta có thể đạt được điều này bằng cách sử dụng php:

Tạo tệp php có tên download.php với mã này:

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

Bây giờ nếu bạn muốn tự động bắt đầu tải xuống pdf, hãy viết javascript này:

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

Nếu bạn muốn cái này hoạt động trên một liên kết, hãy sử dụng cái này ...

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

4
Lưu ý rằng bạn cần phải cẩn thận khi thực hiện việc này với các tham số URL. Ví dụ $file = $_GET['$file'];. Bởi vì sau đó người ta cũng có thể gọi download.php?file=../../../wp-config.phphoặc bất kỳ tài nguyên cụ thể nào khác. Việc kiểm tra thêm các tiện ích mở rộng, loại kịch câm và đường dẫn được phép tải xuống (và loại bỏ những thứ như "../") là rất quan trọng!
Giel Berkers

được nó tôi hay làm <a href='javascript...'> là chính xác giống như đặt trực tiếp vào liên kết trong<a href='download.php'> ?
allan.simon

5

Khi bạn muốn tải trực tiếp bất kỳ hình ảnh hoặc tệp pdf nào từ trình duyệt thay vì mở nó trong tab mới thì trong javascript, bạn nên đặt giá trị cho thuộc tính tải xuống của tạo liên kết động

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

Đối với bản cập nhật Chrome mới, một số sự kiện thời gian không hoạt động. cho rằng mã sau sẽ được sử dụng

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

Thêm con và loại bỏ con chỉ hữu ích cho Firefox, trình duyệt Internet Explorer. Trên chrome, nó sẽ hoạt động mà không cần thêm và xóa con


2

Giải pháp phù hợp nhất với tôi là giải pháp được Nick viết trên blog của anh ấy

Ý tưởng cơ bản về giải pháp của anh ấy là sử dụng mod tiêu đề máy chủ Apache và chỉnh sửa .htaccess để bao gồm chỉ thị FileMatch buộc tất cả các tệp * .pdf hoạt động dưới dạng một luồng thay vì tệp đính kèm. Mặc dù điều này không thực sự liên quan đến việc chỉnh sửa HTML (như câu hỏi ban đầu) nhưng nó không yêu cầu bất kỳ lập trình nào.

Lý do đầu tiên tôi thích cách tiếp cận của Nick là vì nó cho phép tôi đặt nó trên cơ sở từng thư mục để tệp PDF trong một thư mục vẫn có thể được mở trong trình duyệt trong khi cho phép những người khác (những cái chúng tôi muốn người dùng chỉnh sửa rồi tải lên lại) buộc phải tải xuống.

Tôi cũng muốn nói thêm rằng có một tùy chọn với PDF để đăng / gửi các biểu mẫu có thể điền thông qua API đến máy chủ của bạn, nhưng điều đó sẽ mất một thời gian để triển khai.

Lý do thứ hai là vì thời gian là một yếu tố cần cân nhắc. Viết trình xử lý tệp PHP để buộc bố trí nội dung trong header () cũng sẽ mất ít thời gian hơn so với API, nhưng vẫn lâu hơn so với cách tiếp cận của Nick.

Nếu bạn biết cách bật một mod Apache và chỉnh sửa .htaccss, bạn có thể nhận được điều này trong khoảng 10 phút. Nó yêu cầu lưu trữ Linux (không phải Windows). Đây có thể không phải là cách tiếp cận phù hợp cho tất cả các mục đích sử dụng vì nó yêu cầu quyền truy cập máy chủ cấp cao để định cấu hình. Như vậy, nếu bạn đã nói quyền truy cập thì có lẽ vì bạn đã biết cách thực hiện hai điều đó. Nếu không, hãy kiểm tra blog của Nick để biết thêm hướng dẫn.


2

Vì cách html5 (câu trả lời trước đây của tôi) không khả dụng trên tất cả các trình duyệt, có một cách hơi hack khác.

Giải pháp này yêu cầu bạn đang cung cấp tệp dự định từ cùng một miền HOẶC có quyền CORS.

  1. Trước tiên, tải xuống nội dung của tệp qua XMLHttpRequest (Ajax).
  2. Sau đó, tạo một URI dữ liệu bằng cách mã hóa base64 nội dung của tệp và đặt loại phương tiện thành application/octet-stream. Kết quả sẽ như thế nào

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

Bây giờ thiết lập location.href = data. Điều này sẽ khiến trình duyệt tải xuống tệp. Rất tiếc, bạn không thể đặt tên hoặc phần mở rộng tệp theo cách này. Loay hoay với loại phương tiện có thể mang lại điều gì đó.

Xem chi tiết: https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs


1

Tôi cần thực hiện việc này cho các tệp được tạo bằng tên động trong một thư mục cụ thể và được IIS cung cấp.

Điều này đã làm việc cho tôi:

  • Trong IIS, truy cập thư mục đó và nhấp đúp vào Tiêu đề phản hồi HTTP.
  • Thêm tiêu đề mới với thông tin sau:

    Name: content-disposition Value: attachment

(từ: http://forums.iis.net/t/1175103.aspx?add+CustomHeaders+only+for+certain+file+types+ )


1

Nếu bạn đang sử dụng HTML5 (và tôi đoán bây giờ mọi người đều sử dụng nó), có một thuộc tính được gọi là download.

Ví dụ. <a href="somepathto.pdf" download="filename">

đây filenamelà tùy chọn, nhưng nếu được cung cấp, nó sẽ lấy tên này cho tệp đã tải xuống.


Đáng buồn thay, tôi phải thừa nhận rằng tôi quá ngu ngốc để hiểu thẻ này. Tôi đặt điều này: <a href="download/Curriculum_it.pdf.zip">Download curriculum</a>hoặc điều đó: <a href="download/Curriculum_it.pdf.zip" download="Curriculum_it">Download curriculum</a>và tôi có thể thấy hoàn toàn không có sự khác biệt trong cách nó hoạt động. Cả hai tải xuống .zip của tôi. Và trong lần thứ hai sử dụng tùy chọn tên tệp dường như không làm gì cả.
Garavani

0

Hành vi sẽ phụ thuộc vào cách trình duyệt được thiết lập để xử lý các loại MIME khác nhau. Trong trường hợp này, kiểu MIME là application / pdf. Nếu bạn muốn buộc trình duyệt tải xuống tệp, bạn có thể thử buộc một loại MIME khác trên tệp PDF. Tôi khuyên bạn không nên làm điều này vì người dùng sẽ lựa chọn điều gì sẽ xảy ra khi họ mở tệp PDF.


0

Bạn có thể sử dụng download.js ( https://github.com/rndme/downloadhttp://danml.com/download.html ). Nếu tệp nằm trong URL bên ngoài, bạn phải thực hiện một yêu cầu Ajax, nhưng nếu không, thì bạn có thể sử dụng hàm:

download(Path, name, mime)

Đọc tài liệu của họ để biết thêm chi tiết trong GitHub.


Đây là giải pháp javascript tốt nhất để tải xuống ở miền khác.
Edhowler

-1

Cuối cùng tôi đã tìm thấy ...... tạo thẻ neo động và nhấp vào nó

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

'Payment.pdf' chỉ dành cho tên tùy chỉnh.


Không cần phải tạo liên kết động.
Quentin

Lưu ý rằng thuộc tính tải xuống chỉ được hỗ trợ cho các yêu cầu cùng nguồn gốc.
Quentin

Điều này dường như là câu trả lời giống như một này từ ba năm trước đó.
Quentin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.