डाउनलोड फ़ाइल ajax अनुरोध का उपयोग कर


95

जब मैं एक बटन पर क्लिक करता हूं तो मैं "अजाक्स डाउनलोड अनुरोध" भेजना चाहता हूं, इसलिए मैंने इस तरह से कोशिश की:

जावास्क्रिप्ट:

var xhr = new XMLHttpRequest();
xhr.open("GET", "download.php");
xhr.send();

download.php:

<?
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename= file.txt");
header("Content-Transfer-Encoding: binary");    
readfile("file.txt");
?>

लेकिन उम्मीद के मुताबिक काम नहीं करता, मैं कैसे कर सकता हूं? पहले ही, आपका बहुत धन्यवाद


2
यह काम नहीं करेगा, देखें [यह सवाल] [१]। [१]: stackoverflow.com/questions/8771342/…
olegsv

2
क्याlocation.href='download.php';
मूसा

जवाबों:


92

अपडेट 27 अप्रैल, 2015

एचटीएमएल 5 दृश्य में आने और डाउनलोड करने की विशेषता है । यह फ़ायरफ़ॉक्स और क्रोम में समर्थित है, और जल्द ही IE11 में आने के लिए। अपनी आवश्यकताओं के आधार पर, आप AJAX के अनुरोध के बजाय इसका उपयोग कर सकते हैं (या उपयोग कर रहे हैं window.location) जब तक आप जिस फ़ाइल को डाउनलोड करना चाहते हैं वह आपकी साइट के समान मूल पर है।

तुम हमेशा AJAX अनुरोध / कर सकता window.locationका उपयोग करके एक fallback कुछ जावास्क्रिप्ट अगर परीक्षण करने के लिए downloadसमर्थित है और यदि नहीं, स्विचिंग इसे कहते हैं window.location

मूल उत्तर

आपके पास डाउनलोड प्रॉम्प्ट को खोलने के लिए AJAX अनुरोध नहीं हो सकता है क्योंकि आपको डाउनलोड करने के लिए भौतिक रूप से फ़ाइल पर नेविगेट करना होगा। इसके बजाय, आप डाउनलोड करने के लिए नेविगेट करने के लिए एक सफलता फ़ंक्शन का उपयोग कर सकते हैं। php। यह डाउनलोड प्रॉम्प्ट खोलेगा, लेकिन वर्तमान पृष्ठ को नहीं बदलेगा।

$.ajax({
    url: 'download.php',
    type: 'POST',
    success: function() {
        window.location = 'download.php';
    }
});

भले ही यह प्रश्न का उत्तर देता है, यह window.locationपूरी तरह से उपयोग करने और AJAX अनुरोध से पूरी तरह से बचने के लिए बेहतर है ।


39
क्या यह लिंक को दो बार कॉल नहीं करता है? मैं एक समान नाव में हूं ... मैं हेडर में बहुत सारी सुरक्षा जानकारी दे रहा हूं, और सफलता समारोह में फ़ाइल ऑब्जेक्ट को पार्स करने में सक्षम है, लेकिन एक डाउनलोड प्रॉम्प्ट को ट्रिगर करने का तरीका नहीं जानता।
user1447679

3
यह पृष्ठ को दो बार कॉल करता है, इसलिए यदि आप उस पृष्ठ में एक डेटाबेस को क्वेरी कर रहे हैं, तो इसका मतलब है कि डीबी के लिए 2 यात्राएं।
mmmmmm

1
@ user1447679 एक वैकल्पिक समाधान के लिए देखें: stackoverflow.com/questions/38665947/…
John

1
मुझे समझाएं कि इससे मुझे कैसे मदद मिली ... उदाहरण और अधिक पूर्ण हो सकता था। "download.php? get_file = true" या कुछ और के साथ ... मेरे पास एक अजाक्स फ़ंक्शन है जो फॉर्म सबमिट करने पर कुछ त्रुटि की जाँच करता है और फिर एक सीएसवी फ़ाइल बनाता है। यदि त्रुटि जांच विफल हो जाती है, तो इसे वापस आना होगा क्योंकि यह विफल क्यों हुआ। यदि यह CSV बनाता है तो यह माता-पिता से कह रहा है कि "आगे बढ़ें और फ़ाइल लाएँ"। मैं करता हूँ कि फार्म चर के साथ अजाक्स फ़ाइल पर पोस्ट करके फिर उसी फ़ाइल में एक अलग पैरामीटर पोस्ट करते हुए कहा "मुझे वह फ़ाइल जो आपने अभी बनाई है" (पथ / नाम को अजाक्स फ़ाइल में हार्ड कोड किया गया है)।
स्कॉट

4
लेकिन यह 2 बार अनुरोध भेजेगा, यह उचित नहीं है
धर्मेंद्रसिंह चुडासमा

43

आपको वास्तव में इसके लिए अजाक्स की आवश्यकता नहीं है। यदि आप बटन पर href के रूप में "download.php" सेट करते हैं, या, यदि यह लिंक उपयोग नहीं है:

window.location = 'download.php';

ब्राउज़र को बाइनरी डाउनलोड को पहचानना चाहिए और वास्तविक पृष्ठ को लोड नहीं करना चाहिए, लेकिन बस डाउनलोड के रूप में फ़ाइल की सेवा करें।


3
परिवर्तन के लिए आप जिस प्रोग्रामिंग भाषा का उपयोग कर रहे हैं, window.location वह जावास्क्रिप्ट है।
मिकमेकाना

1
आप सही हैं @ मिकमेककाना, मेरा वास्तव में अजाक्स का मतलब है :)।
जेले क्राल्ट

2
एक समाधान के लिए उच्च और निम्न शिकार कर रहे हैं और यह बहुत सुंदर और सही है। बहुत बहुत धन्यवाद।
यांग्शुन टाय

2
बेशक, यह समाधान केवल तभी काम करेगा जब यह एक स्थिर फ़ाइल है जो पहले से मौजूद है।
क्रिलगर

1
यदि सर्वर एक त्रुटि के साथ प्रतिक्रिया करता है, तो ब्राउज़र द्वारा किसी त्रुटि पृष्ठ पर पुनर्निर्देशित किए बिना आपके मुख्य पृष्ठ पर बने रहने का कोई तरीका नहीं होगा। कम से कम इस क्रोम जब विंडो स्थान का परिणाम देता है 404. क्या करता है
इयान

43

ब्राउज़र को एक फ़ाइल डाउनलोड करने के लिए आपको उस तरह का अनुरोध करना होगा:

 function downloadFile(urlToSend) {
     var req = new XMLHttpRequest();
     req.open("GET", urlToSend, true);
     req.responseType = "blob";
     req.onload = function (event) {
         var blob = req.response;
         var fileName = req.getResponseHeader("fileName") //if you have the fileName header available
         var link=document.createElement('a');
         link.href=window.URL.createObjectURL(blob);
         link.download=fileName;
         link.click();
     };

     req.send();
 }

7
यह मेरे लिए काम करता है, लेकिन फ़ायरफ़ॉक्स में, मुझे पहली बार DOM में <a> टैग लगाने की ज़रूरत थी, और फ़ाइल को स्वचालित रूप से डाउनलोड करने के लिए फ्लाई पर एक बनाने के बजाय इसे मेरे लिंक के रूप में संदर्भित करें।
एरिक डोनोहू

काम करता है लेकिन अगर निष्पादन के दौरान फ़ाइल बना रहा है तो क्या होता है? यह काम नहीं करता है जब फ़ाइल पहले से ही बनाई गई है।
डिएगो

@ ताहा मैंने इसे एज पर टेस्ट किया और यह काम करने लगा। हालांकि IE के बारे में पता नहीं है। मेरा ग्राहक IE उपयोगकर्ताओं को लक्षित नहीं करता ;-) क्या मैं भाग्यशाली हूं? : D
Sain Dошƒаӽ

1
@ErikDonohoo आप <a>जेएस के साथ टैग बना सकते हैं , "मक्खी पर" और साथ ही साथ इसे जोड़ सकते हैं document.body। आप निश्चित रूप से एक ही समय में इसे छिपाना चाहते हैं।
मेर्टन तमसे

धन्यवाद @ जोओ, मैं बहुत लंबे समय से इस समाधान की तलाश में था।
अभिषेक घराने

20

क्रॉस ब्राउज़र समाधान, क्रोम, फ़ायरफ़ॉक्स, एज, IE11 पर परीक्षण किया गया।

DOM में, एक छिपा हुआ लिंक टैग जोड़ें:

<a id="target" style="display: none"></a>

फिर:

var req = new XMLHttpRequest();
req.open("GET", downloadUrl, true);
req.responseType = "blob";
req.setRequestHeader('my-custom-header', 'custom-value'); // adding some headers (if needed)

req.onload = function (event) {
  var blob = req.response;
  var fileName = null;
  var contentType = req.getResponseHeader("content-type");

  // IE/EDGE seems not returning some response header
  if (req.getResponseHeader("content-disposition")) {
    var contentDisposition = req.getResponseHeader("content-disposition");
    fileName = contentDisposition.substring(contentDisposition.indexOf("=")+1);
  } else {
    fileName = "unnamed." + contentType.substring(contentType.indexOf("/")+1);
  }

  if (window.navigator.msSaveOrOpenBlob) {
    // Internet Explorer
    window.navigator.msSaveOrOpenBlob(new Blob([blob], {type: contentType}), fileName);
  } else {
    var el = document.getElementById("target");
    el.href = window.URL.createObjectURL(blob);
    el.download = fileName;
    el.click();
  }
};
req.send();

अच्छा जेनेरिक कोड। @leo आप इस कोड को कस्टम हेडर जैसे जोड़कर सुधार सकते हैं Authorization?
vibs2006

1
धन्यवाद @ एलो। इसके सहायक। इसके window.URL.revokeObjectURL(el.href);बाद आप क्या जोड़ना el.click()चाहते हैं?
vibs2006

यदि सामग्री विवाद एक गैर-UTF8 फ़ाइल नाम निर्दिष्ट करता है तो फ़ाइल नाम गलत होगा।
मैथ्यू एल्डन

14

हो सकता है। आप डाउनलोड कर सकते हैं एक अजाक्स फ़ंक्शन के अंदर से, उदाहरण के लिए, .csv फ़ाइल बनने के बाद।

मेरे पास एक अजाक्स फ़ंक्शन है जो एक .csv फ़ाइल के लिए संपर्कों का एक डेटाबेस निर्यात करता है, और बस खत्म होने के बाद, यह स्वचालित रूप से .csv फ़ाइल डाउनलोड शुरू करता है। इसलिए, जब मुझे responseText मिलता है और सब कुछ ठीक होता है, तो मैं ब्राउज़र को इस तरह रीडायरेक्ट करता हूं:

window.location="download.php?filename=export.csv";

मेरी डाउनलोड। Php फाइल इस तरह दिखती है:

<?php

    $file = $_GET['filename'];

    header("Cache-Control: public");
    header("Content-Description: File Transfer");
    header("Content-Disposition: attachment; filename=".$file."");
    header("Content-Transfer-Encoding: binary");
    header("Content-Type: binary/octet-stream");
    readfile($file);

?>

कोई पृष्ठ ताज़ा नहीं है और फ़ाइल स्वचालित रूप से डाउनलोड होना शुरू हो जाती है।

नोट - निम्नलिखित ब्राउज़रों में परीक्षण किया गया:

Chrome v37.0.2062.120 
Firefox v32.0.1
Opera v12.17
Internet Explorer v11

1
क्या यह खतरनाक सुरक्षा-वार नहीं है?
मिकेल बर्जरॉन नेरॉन

@ मिकेलबर्गरनॉन क्यों?
पेद्रो सोसा

5
मुझे ऐसा लगता है क्योंकि कोई भी डाउनलोड। Php? फ़ाइल नाम = [कुछ] को कॉल कर सकता है और कुछ पथ और फ़ाइल नाम, विशेष रूप से आम लोगों की कोशिश कर सकता है, और यह एक प्रोग्राम या स्क्रिप्ट के भीतर लूप के अंदर भी किया जा सकता है।
मिकेल बर्जरॉन नेरॉन

नहीं .htaccess से बचना होगा?
पेड्रो सोसा

9
@PedroSousa .. नहीं। htaccess अपाचे के माध्यम से फ़ाइल संरचना तक पहुंच को नियंत्रित करता है। चूंकि पहुंच PHP स्क्रिप्ट तक पहुंच गई है, इसलिए htaccess अब अपना कर्तव्य बंद कर देता है। यह एक सुरक्षा छेद है क्योंकि वास्तव में, कोई भी फाइल जिसे PHP (और इसके तहत चलाया जा रहा है) उपयोगकर्ता पढ़ सकता है, इसलिए यह रीडफ़ाइल में वितरित कर सकता है ... किसी को हमेशा पढ़ने के लिए अनुरोधित फ़ाइल को साफ करना चाहिए
Prof83


0

शीर्ष लेख से फ़ाइल नाम डिकोड करना थोड़ा अधिक जटिल है ...

    var filename = "default.pdf";
    var disposition = req.getResponseHeader('Content-Disposition');

    if (disposition && disposition.indexOf('attachment') !== -1) 
    {
       var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
       var matches = filenameRegex.exec(disposition);

       if (matches != null && matches[1]) 
           filename = matches[1].replace(/['"]/g, '');
    }

3
कृपया अपने पूरे कोड ब्लॉक को प्रारूपित करें और भविष्य के पाठक लाभ के लिए अपनी प्रक्रिया को कुछ अतिरिक्त विवरण प्रदान करें।
मिकमैकुसा

0

यह समाधान उपरोक्त लोगों से बहुत अलग नहीं है, लेकिन मेरे लिए यह बहुत अच्छा काम करता है और मुझे लगता है कि यह साफ है।

मैं बेस 64 को सुझाव देता हूं कि फाइल सर्वर साइड (बेस 64_एन्कोड) (यदि आप PHP का उपयोग कर रहे हैं) को एनकोड करें और क्लाइंट को बेस 64 एनकोडेड डेटा भेजें

क्लाइंट पर आप ऐसा करते हैं:

 let blob = this.dataURItoBlob(THE_MIME_TYPE + "," + response.file);
 let uri = URL.createObjectURL(blob);
 let link = document.createElement("a");
 link.download = THE_FILE_NAME,
 link.href = uri;
 document.body.appendChild(link);
 link.click();
 document.body.removeChild(link);

यह कोड एक लिंक में एन्कोडेड डेटा डालता है और लिंक पर एक क्लिक का अनुकरण करता है, फिर इसे हटा देता है।


आप बस किसी टैग को छिपा सकते हैं और गतिशील रूप से href को पॉप्युलेट कर सकते हैं। जोड़ने और हटाने की जरूरत नहीं
बीपीएलए

0

आपकी आवश्यकताओं को कवर किया गया है, window.location('download.php');
लेकिन मुझे लगता है कि आपको डाउनलोड करने के लिए फ़ाइल को पास करने की आवश्यकता है, हमेशा एक ही फ़ाइल को डाउनलोड न करें, और इसीलिए आप एक अनुरोध का उपयोग कर रहे हैं, एक विकल्प यह है कि php फ़ाइल को showfile.php और सरल के रूप में बनाएं जैसे निवेदन करना

var myfile = filetodownload.txt
var url = "shofile.php?file=" + myfile ;
ajaxRequest.open("GET", url, true);

showfile.php

<?php
$file = $_GET["file"] 
echo $file;

फ़ाइल कहाँ फ़ाइल नाम गेट या पोस्ट के माध्यम से अनुरोध में पारित किया है और फिर एक समारोह में प्रतिक्रिया को बस पकड़

if(ajaxRequest.readyState == 4){
                        var file = ajaxRequest.responseText;
                        window.location = 'downfile.php?file=' + file;  
                    }
                }

0

अजाक्स में वेब पेज डाउनलोड करने का एक और उपाय है। लेकिन मैं एक ऐसे पृष्ठ की बात कर रहा हूँ जिसे पहले संसाधित किया जाना चाहिए और फिर डाउनलोड किया जाना चाहिए।

सबसे पहले आपको परिणाम डाउनलोड से पेज प्रोसेसिंग को अलग करना होगा।

1) अजाक्स कॉल में केवल पृष्ठ गणना की जाती है।

$ .post ("CalculusPage.php", {calculusFunction: true, ID: 29, data1: "a", data2: "b"},

       फ़ंक्शन (डेटा, स्थिति) 
       {
            अगर (स्थिति == "सफलता") 
            {
                / * 2) उत्तर में वह पृष्ठ जो पिछली गणनाओं का उपयोग करता है, डाउनलोड किया जाता है। उदाहरण के लिए, यह एक पृष्ठ हो सकता है जो अजाक्स कॉल में गणना की गई तालिका के परिणामों को प्रिंट करता है। * /
                window.location.href = DownloadPage.php + "; ID =" + 29;
            }               
       }
);

// उदाहरण के लिए: कैल्क्युपासपेज.फैप में

    यदि (खाली ($ _ POST ["कलन विधि"])) 
    {
        $ आईडी = $ _POST ["आईडी"];

        $ क्वेरी = "INSERT INTO ExamplePage (data1, data2) VALUES ('"। $ _ POST ["data1"]। "', '"। $ _ POST ["data2"] "" "WHERE id =" $ ID;
        ...
    }

// उदाहरण के लिए: DownloadPage.php में

    $ आईडी = $ _GET ["आईडी"];

    $ sede = "Select * FROM ExamplePage WHERE id ="; $ ID;
    ...

    $ फ़ाइल नाम = "Export_Data.xls";
    शीर्ष लेख ("सामग्री-प्रकार: अनुप्रयोग / vnd.ms-excel");
    शीर्ष लेख ("सामग्री-विवाद: इनलाइन; फ़ाइल नाम = $ फ़ाइल नाम");

    ...

मुझे उम्मीद है कि यह समाधान कई लोगों के लिए उपयोगी हो सकता है, क्योंकि यह मेरे लिए था।


0

अधिक आधुनिक दृष्टिकोण की तलाश करने वालों के लिए, आप इसका उपयोग कर सकते हैं fetch API। निम्न उदाहरण दिखाता है कि स्प्रेडशीट फ़ाइल को कैसे डाउनलोड किया जाए। यह आसानी से निम्नलिखित कोड के साथ किया जाता है।

fetch(url, {
    body: JSON.stringify(data),
    method: 'POST',
    headers: {
        'Content-Type': 'application/json; charset=utf-8'
    },
})
.then(response => response.blob())
.then(response => {
    const blob = new Blob([response], {type: 'application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
    const downloadUrl = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = downloadUrl;
    a.download = "file.xlsx";
    document.body.appendChild(a);
    a.click();
})

मेरा मानना ​​है कि इस दृष्टिकोण को अन्य XMLHttpRequestसमाधानों की तुलना में समझना बहुत आसान है । इसके अलावा, यह jQueryदृष्टिकोण के लिए एक समान वाक्यविन्यास है , बिना किसी अतिरिक्त पुस्तकालयों को जोड़ने की आवश्यकता के बिना।

निश्चित रूप से, मैं आपको सलाह दूंगा कि आप किस ब्राउज़र को विकसित कर रहे हैं, क्योंकि यह नया दृष्टिकोण IE पर काम नहीं करेगा। आप निम्न लिंक पर पूर्ण ब्राउज़र संगतता सूची पा सकते हैं ।

महत्वपूर्ण : इस उदाहरण में मैं दिए गए सर्वर पर एक JSON अनुरोध भेज रहा हूं url। इसे urlसेट किया जाना चाहिए, मेरे उदाहरण पर मैं आपको इस भाग को जानता हूं। इसके अलावा, काम करने के आपके अनुरोध के लिए आवश्यक हेडर पर विचार करें। चूँकि मैं JSON भेज रहा हूँ, मुझे Content-Typeहेडर जोड़ना होगा और इसे सेट करना होगा application/json; charset=utf-8, जैसा कि सर्वर को यह पता चलेगा कि उसे किस प्रकार का अनुरोध प्राप्त होगा।


0

@ जोआओ मार्कोस समाधान मेरे लिए काम करता है लेकिन मुझे IE पर काम करने के लिए कोड को संशोधित करना पड़ा, अगर कोड कैसा दिखता है तो नीचे

       downloadFile(url,filename) {
        var that = this;
        const extension =  url.split('/').pop().split('?')[0].split('.').pop();

        var req = new XMLHttpRequest();
        req.open("GET", url, true);
        req.responseType = "blob";
        req.onload = function (event) {
            const fileName = `${filename}.${extension}`;
            const blob = req.response;

            if (window.navigator.msSaveBlob) { // IE
                window.navigator.msSaveOrOpenBlob(blob, fileName);
            } 
            const link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);                
            link.download = fileName;
            link.click();
            URL.revokeObjectURL(link.href);

        };

        req.send();
    },
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.