2008-12-13 41 views
51

Giả sử tôi có liên kết tải xuống cho tệp trên trang web của mình.bắt đầu tải xuống tệp bằng JavaScript

Khi nhấp vào các liên kết này gửi yêu cầu AJAX đến máy chủ trả về URL có vị trí của tệp.

Điều tôi muốn làm là hướng trình duyệt tải xuống tệp khi phản hồi được trả về. Có cách nào để thực hiện điều này không?

Trả lời

3

Hãy thử lib này https://github.com/PixelsCommander/Download-File-JS hiện đại hơn tất cả các giải pháp được mô tả trước đây vì sử dụng thuộc tính "tải xuống" và kết hợp các phương pháp để mang lại trải nghiệm tốt nhất có thể.

giải thích tại đây - http://pixelscommander.com/en/javascript/javascript-file-downliading-ignore-content-type/

Có vẻ là mảnh lý tưởng của mã để bắt đầu tải xuống trong JavaScript.

2

Tôi đề xuất tạo khung nội tuyến ẩn trên trang và đặt src thành url bạn đã nhận được từ máy chủ - tải xuống sẽ bắt đầu mà không cần tải lại trang.

Hoặc bạn chỉ có thể đặt document.location.href hiện tại thành địa chỉ url đã nhận. Nhưng điều đó có thể khiến người dùng gặp lỗi nếu tài liệu được yêu cầu thực sự không tồn tại.

+0

khi nó sẽ được an toàn để loại bỏ các iframe từ DOM? – AMember

3

Đồng ý với các phương pháp được đề cập bởi maxnk, tuy nhiên bạn có thể muốn xem xét lại việc cố gắng tự động buộc trình duyệt tải xuống URL. Nó có thể hoạt động tốt cho các tệp nhị phân nhưng đối với các loại tệp khác (văn bản, PDF, hình ảnh, video), trình duyệt có thể muốn hiển thị nó trong cửa sổ (hoặc IFRAME) thay vì lưu vào đĩa.

Nếu bạn thực sự cần thực hiện cuộc gọi Ajax để nhận các liên kết tải xuống cuối cùng, điều gì về việc sử dụng DHTML để tự động ghi liên kết tải xuống (từ phản hồi ajax) vào trang? Bằng cách đó, người dùng có thể nhấp vào nó để tải xuống (nếu nhị phân) hoặc xem trong trình duyệt của họ - hoặc chọn "Lưu dưới dạng" trên liên kết để lưu vào đĩa. Đó là một nhấp chuột bổ sung, nhưng người dùng có nhiều quyền kiểm soát hơn.

+0

Ồ, vâng, tôi đã quên mất không phải nhị phân, cảm ơn bạn. Là một giải pháp thay thế có thể là giải pháp tốt để tạo một trình bao bọc xung quanh dòng phim từ máy chủ và đặt tiêu đề "Nội dung-Bố trí: tệp đính kèm". Nhưng nó chỉ thích hợp cho các tệp nhỏ. – maxnk

+0

Hoặc bạn có thể thử đánh lừa trình duyệt nghĩ rằng tệp có thể tải xuống là nhị phân nhờ máy chủ gửi tiêu đề "Loại nội dung" dưới dạng "ứng dụng/octet-stream", bất kể loại tệp thực tế –

+1

Internet Explorer 8 chặn tải xuống tệp sử dụng tất cả các cách được đề cập (iframe, window.location.href hoặc thậm chí "http-equiv = REFRESH CONTENT"). "Để giúp bảo vệ an ninh của bạn, IE đã chặn trang web này tải xuống tệp xuống máy tính của bạn ...". Bạn có biết cách ngăn chặn cảnh báo này và bắt đầu tải xuống như Firefox không? Tôi đã kiểm tra một số trang web: Skype, Google (với Picasa) và Download.com gây ra cảnh báo khi bạn tải xuống (vì chúng hiển thị một loại trang "cảm ơn"). Cảm ơn những suy nghĩ của bạn! – Mar

1

Tôi muốn đề xuất window.open() để mở cửa sổ bật lên. Nếu đó là bản tải xuống, sẽ không có cửa sổ và bạn sẽ nhận được tệp của mình. Nếu có một 404 hoặc một cái gì đó, người dùng sẽ thấy nó trong một cửa sổ mới (do đó, công việc của họ sẽ không bị làm phiền, nhưng họ vẫn sẽ nhận được một thông báo lỗi).

+1

hoạt động tốt nếu bạn đang giao dịch với một người dùng nhấp vào liên kết (nhưng sau đó tại sao có nó thậm chí là js?) Nó vẫn sẽ chạy vào vi phạm an ninh IE. – Laith

10

Nếu đây là ứng dụng máy chủ của riêng bạn sau đó tôi đề nghị sử dụng các tiêu đề sau đây

Content-disposition: attachment; filename=fname.ext 

Điều này sẽ buộc bất kỳ trình duyệt để tải về các tập tin và không làm cho nó trong cửa sổ trình duyệt.

7

Chỉ cần gọi window.location.href = new_url từ javascript của bạn và nó sẽ chuyển hướng trình duyệt với URL như người dùng đã gõ đó vào thanh địa chỉ

+1

Đã xảy ra sự cố tương tự. Giải pháp của bạn đã làm các trick. Cảm ơn! –

26

Chúng tôi làm điều đó theo cách đó: Đầu tiên thêm kịch bản này.

<script type="text/javascript"> 
function populateIframe(id,path) 
{ 
    var ifrm = document.getElementById(id); 
    ifrm.src = "download.php?path="+path; 
} 
</script> 

Nơi này, nơi bạn muốn nút tải (ở đây chúng tôi sử dụng chỉ là một liên kết):

<iframe id="frame1" style="display:none"></iframe> 
<a href="javascript:populateIframe('frame1','<?php echo $path; ?>')">download</a> 

File 'download.php' (cần phải được đặt trên máy chủ của bạn) chỉ đơn giản bao gồm:

<?php 
    header("Content-Type: application/octet-stream"); 
    header("Content-Disposition: attachment; filename=".$_GET['path']); 
    readfile($_GET['path']); 
?> 

Vì vậy, khi bạn nhấp vào liên kết, iframe ẩn sẽ nhận/mở tệp nguồn 'download.php'. Với đường dẫn lấy tham số. Chúng tôi nghĩ đây là giải pháp tốt nhất!

Cần lưu ý rằng phần PHP của giải pháp này là một minh chứng đơn giản và có khả năng rất, rất không an toàn. Nó cho phép người dùng tải xuống bất kỳ tệp nào, không chỉ là một tập hợp được xác định trước.Điều đó có nghĩa họ có thể tải về các bộ phận của mã nguồn của trang web riêng của mình, có thể chứa thông tin API, vv

+2

hay nhưng ... làm thế nào để bạn xử lý lỗi 404 theo cách này? –

+6

@Fabio: 'if (! File_exists ($ path)) {header (" HTTP/1.1 404 Không tìm thấy "); lối thoát; } 'nên làm các trick –

+0

là có cách nào cho javascript để biết tiến trình tải xuống (hoặc đơn giản là có hay không nó hoàn thành)? – lakenen

18

Tôi đã tạo ra một mã nguồn mở jQuery File Download plugin (Demo with examples) (GitHub) mà cũng có thể giúp đỡ với tình hình của bạn. Nó hoạt động khá giống với iframe nhưng có một số tính năng thú vị mà tôi thấy khá tiện dụng:

  • Người dùng không bao giờ rời khỏi trang mà họ đã bắt đầu tải xuống tệp. Tính năng này đang trở thành rất quan trọng cho các ứng dụng web hiện đại
  • Tested hỗ trợ trình duyệt chéo (bao gồm cả điện thoại di động!)
  • Nó hỗ trợ POST và GET yêu cầu trong một cách tương tự như API AJAX của jQuery
  • successCallback và failCallback chức năng cho phép bạn trở thành rõ ràng về những gì người dùng nhìn thấy trong cả hai trường hợp
  • Cùng với giao diện người dùng jQuery, nhà phát triển có thể dễ dàng hiển thị phương thức cho người dùng biết rằng tệp đang tải xuống, giải thể phương thức sau khi quá trình tải xuống bắt đầu hoặc thậm chí thông báo cho người dùng một cách thân thiện một lỗi đã xảy ra. Xem Demo cho một ví dụ về điều này.
+0

Cảm ơn jQuery File Download plugin rất hữu ích cho tôi .. –

+0

Xin chào. Có cách nào để ngăn Internet Explorer 8 chặn việc tải xuống không? Internet Explorer Information Bar yêu cầu xác nhận tải xuống làm cho trang được tải lại và không tải lại, với kết quả là người dùng phải nhấp lại vào liên kết tải xuống. Cảm ơn trước – Pierpaolo

+0

Đây chỉ là những gì tôi cần. Cảm ơn bạn! – Tobia

14

Đọc câu trả lời - bao gồm câu trả lời được chấp nhận Tôi muốn chỉ ra các tác động bảo mật của việc truyền đường dẫn trực tiếp đến readfile qua GET.

Nó có vẻ hiển nhiên đối với một số nhưng một số có thể chỉ cần sao chép/dán mã này:

<?php 
    header("Content-Type: application/octet-stream"); 
    header("Content-Disposition: attachment; filename=".$_GET['path']); 
    readfile($_GET['path']); 
?> 

Vậy điều gì sẽ xảy ra nếu tôi vượt qua một cái gì đó như '/ path/to/fileWithSecrets' để kịch bản này? Tập lệnh đã cho sẽ gửi bất kỳ tệp nào mà người dùng máy chủ web có quyền truy cập vào.

Vui lòng tham khảo thảo luận này để biết thông tin làm thế nào để ngăn chặn điều này: How do I make sure a file path is within a given subdirectory?

+1

Liên kết trực tiếp đến tệp trong iframe và đặt tiêu đề trong htaccess. –

1

Tại sao cậu lại làm cho phía máy chủ thứ khi tất cả bạn cần là để chuyển hướng trình duyệt để window.location.href khác nhau?

Dưới đây là mã phân tích file = QueryString (taken from this question) và chuyển hướng người dùng đến địa chỉ đó trong 1 giây (chỉ hoạt động đối với tôi thậm chí trên các trình duyệt Android):

<script type="text/javascript"> 
    var urlParams; 
    (window.onpopstate = function() { 
     var match, 
     pl = /\+/g, // Regex for replacing addition symbol with a space 
     search = /([^&=]+)=?([^&]*)/g, 
     decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, 
     query = window.location.search.substring(1); 

     urlParams = {}; 
     while (match = search.exec(query)) 
      urlParams[decode(match[1])] = decode(match[2]); 
    })(); 

    (window.onload = function() { 
     var path = urlParams["file"]; 
     setTimeout(function() { document.location.href = path; }, 1000); 
    }); 
</script> 

Nếu bạn có jQuery trong dự án của bạn chắc chắn loại bỏ các window.onpopstate & xử lý window.onload và làm mọi thứ trong $ (document) .ready (function() {});

3

Để khắc phục lỗ hổng bảo mật trong câu trả lời được bình chọn hàng đầu, bạn có thể đặt iframe src trực tiếp vào tệp bạn muốn (thay vì tệp php trung gian) và đặt thông tin tiêu đề trong.tệp htaccess:

<Files *.apk> 
    ForceType application/force-download 
    Header set Content-Disposition attachment 
    Header set Content-Type application/vnd.android.package-archive 
    Header set Content-Transfer-Encoding binary 
</Files> 
2

Liên quan đến câu trả lời hàng đầu Tôi có thể có giải pháp cho rủi ro bảo mật.

<?php 
    if(isset($_GET['path'])){ 
     if(in_array($_GET['path'], glob("*/*.*"))){ 
      header("Content-Type: application/octet-stream"); 
      header("Content-Disposition: attachment; filename=".$_GET['path']); 
      readfile($_GET['path']); 
     } 
    } 
?> 

Sử dụng hàm glob() (Tôi đã kiểm tra tệp tải xuống trong đường dẫn một thư mục từ tệp cần tải xuống) Tôi có thể tạo một loạt tệp được "cho phép" tải xuống và kiểm tra con đường đi qua chống lại nó. Điều này không chỉ đảm bảo rằng các tập tin được lấy không phải là một cái gì đó nhạy cảm mà còn kiểm tra sự tồn tại của tập tin cùng một lúc.

~ Lưu ý: Javascript/HTML ~

HTML:

<iframe id="download" style="display:none"></iframe> 

<input type="submit" value="Download" onclick="ChangeSource('document_path');return false;"> 

JavaScript:

<script type="text/javascript"> 
    <!-- 
     function ChangeSource(path){ 
      document.getElementByID('download').src = 'path_to_php?path=' + document_path; 
     } 
    --> 
</script> 
+2

Đây là PHP .... Anh ấy hỏi JavaScript: P –

+0

Phải nhưng điều này đã được xây dựng trên câu trả lời hàng đầu. Tuy nhiên, tôi sẽ thêm vào một kết nối JavaScript tương tự. –

Các vấn đề liên quan