2009-07-09 18 views
395

मेरे पास एक ऐसा पृष्ठ है जो उपयोगकर्ता को गतिशील रूप से जेनरेट की गई फ़ाइल डाउनलोड करने की अनुमति देता है। उत्पन्न करने में काफी समय लगता है, इसलिए मैं एक "प्रतीक्षा" संकेतक दिखाना चाहता हूं। समस्या यह है कि, मुझे पता नहीं लगा सकता कि ब्राउज़र को फ़ाइल कब प्राप्त हुई है, इसलिए मैं संकेतक को छुपा सकता हूं।पता लगाएं कि ब्राउज़र को फ़ाइल डाउनलोड कब प्राप्त होता है

मैं एक छिपे हुए फॉर्म में अनुरोध कर रहा हूं, जो सर्वर पर पोस्ट करता है, और इसके परिणामों के लिए एक छिपा हुआ आईफ्रेम लक्षित करता है। ऐसा इसलिए है कि मैं परिणाम के साथ पूरी ब्राउज़र विंडो को प्रतिस्थापित नहीं करता हूं। मैं आईफ्रेम पर "लोड" ईवेंट सुनता हूं, उम्मीद है कि डाउनलोड पूर्ण हो जाने पर यह आग लग जाएगी।

मैं फ़ाइल के साथ "सामग्री-विस्थापन: अनुलग्नक" शीर्षलेख लौटाता हूं, जिससे ब्राउज़र "सहेजें" संवाद दिखाता है। लेकिन ब्राउज़र आईफ्रेम में "लोड" ईवेंट नहीं चलाता है।

मैंने कोशिश की एक दृष्टिकोण एक बहु-पक्ष प्रतिक्रिया का उपयोग कर रहा है। तो यह एक खाली HTML फ़ाइल, साथ ही संलग्न डाउनलोड करने योग्य फ़ाइल भेज देगा। उदाहरण के लिए:

Content-type: multipart/x-mixed-replace;boundary="abcde" 

--abcde 
Content-type: text/html 

--abcde 
Content-type: application/vnd.fdf 
Content-Disposition: attachment; filename=foo.fdf 

file-content 
--abcde 

यह फ़ायरफ़ॉक्स में काम करता है; यह खाली HTML फ़ाइल प्राप्त करता है, "लोड" ईवेंट को सक्रिय करता है, फिर डाउनलोड करने योग्य फ़ाइल के लिए "सहेजें" संवाद दिखाता है। लेकिन यह आईई और सफारी पर विफल रहता है; आईई "लोड" घटना को फायर करता है लेकिन फ़ाइल डाउनलोड नहीं करता है, और सफारी फ़ाइल डाउनलोड करता है (गलत नाम और सामग्री-प्रकार के साथ), और "लोड" ईवेंट को आग नहीं करता है।

फ़ाइल निर्माण शुरू करने के लिए कॉल करने के लिए एक अलग दृष्टिकोण हो सकता है, फिर सर्वर तैयार होने तक मतदान करें, फिर पहले से बनाई गई फ़ाइल डाउनलोड करें। लेकिन मैं सर्वर पर अस्थायी फ़ाइलों को बनाने से बचाना चाहता हूं।

क्या किसी के पास कोई बेहतर विचार है?

+3

IE के कोई संस्करण बहुखण्डीय/एक्स मिश्रित की जगह का समर्थन करता है। – EricLaw

+0

धन्यवाद एरिक - यह जानना अच्छा है। मैं उस दृष्टिकोण के साथ और अधिक समय बर्बाद नहीं करूंगा। –

+0

केवल विश्वसनीय तरीका सर्वर पुश अधिसूचना (एएसपी.नेट लोगों के लिए सिग्नलआर) प्रतीत होता है। – dudeNumber4

उत्तर

371

एक possible solution क्लाइंट पर JavaScript का उपयोग करता है।

ग्राहक एल्गोरिथ्म:

  1. एक यादृच्छिक अद्वितीय टोकन जेनरेट करें।
  2. डाउनलोड अनुरोध जमा करें, और एक GET/POST फ़ील्ड में टोकन शामिल करें।
  3. "प्रतीक्षा" सूचक दिखाएं।
  4. टाइमर शुरू करें, और हर सेकेंड या तो, "fileDownloadToken" नामक कुकी की तलाश करें (या जो भी आप तय करते हैं)।
  5. यदि कुकी मौजूद है, और इसका मान टोकन से मेल खाता है, तो "प्रतीक्षा" संकेतक को छुपाएं।

सर्वर एल्गोरिथ्म: अनुरोध में प्राप्त/पोस्ट क्षेत्र के लिए

  1. देखो।
  2. यदि इसका कोई खाली मूल्य नहीं है, तो कुकी छोड़ें (उदा। "फ़ाइलडाउनलोड टोकन"), और इसके मान को टोकन के मान पर सेट करें।

ग्राहक स्रोत कोड (जावास्क्रिप्ट):

function getCookie(name) { 
    var parts = document.cookie.split(name + "="); 
    if (parts.length == 2) return parts.pop().split(";").shift(); 
} 

function expireCookie(cName) { 
    document.cookie = 
     encodeURIComponent(cName) + "=deleted; expires=" + new Date(0).toUTCString(); 
} 

function setCursor(docStyle, buttonStyle) { 
    document.getElementById("doc").style.cursor = docStyle; 
    document.getElementById("button-id").style.cursor = buttonStyle; 
} 

function setFormToken() { 
    var downloadToken = new Date().getTime(); 
    document.getElementById("downloadToken").value = downloadToken; 
    return downloadToken; 
} 

var downloadTimer; 
var attempts = 30; 

// Prevents double-submits by waiting for a cookie from the server. 
function blockResubmit() { 
    var downloadToken = setFormToken(); 
    setCursor("wait", "wait"); 

    downloadTimer = window.setInterval(function() { 
     var token = getCookie("downloadToken"); 

     if((token == downloadToken) || (attempts == 0)) { 
      unblockSubmit(); 
     } 

     attempts--; 
    }, 1000); 
} 

function unblockSubmit() { 
    setCursor("auto", "pointer"); 
    window.clearInterval(downloadTimer); 
    expireCookie("downloadToken"); 
    attempts = 30; 
} 

उदाहरण सर्वर कोड (PHP):

$TOKEN = "downloadToken"; 

// Sets a cookie so that when the download begins the browser can 
// unblock the submit button (thus helping to prevent multiple clicks). 
// The false parameter allows the cookie to be exposed to JavaScript. 
$this->setCookieToken($TOKEN, $_GET[ $TOKEN ], false); 

$result = $this->sendFile(); 

कहाँ:

public function setCookieToken(
    $cookieName, $cookieValue, $httpOnly = true, $secure = false) { 

    // See: http://stackoverflow.com/a/1459794/59087 
    // See: http://shiflett.org/blog/2006/mar/server-name-versus-http-host 
    // See: http://stackoverflow.com/a/3290474/59087 
    setcookie(
     $cookieName, 
     $cookieValue, 
     2147483647,   // expires January 1, 2038 
     "/",     // your path 
     $_SERVER["HTTP_HOST"], // your domain 
     $secure,    // Use true over HTTPS 
     $httpOnly    // Set true for $AUTH_COOKIE_NAME 
    ); 
} 
+4

बहुत बढ़िया विचार, मैंने इसे मूल रूपरेखा के रूप में उपयोग किया [इस उत्तर के लिए] (http://stackoverflow.com/a/9049986/585552) jQuery/C# – Greg

+1

के साथ कई फ़ाइलों को डाउनलोड करने के लिए बाउट, एस 3 पर फ़ाइलों के साथ संभव नहीं है क्योंकि आप कुकीज़ सेट नहीं कर सकते हैं। – jedierikb

+5

दूसरों के लिए एक सिर: यदि दस्तावेज़.cookies में डाउनलोड टोकन शामिल नहीं है, तो कुकी पथ की जांच करें। मेरे मामले में, मुझे सर्वर पर "/" पथ को सेट करना था (उदाहरण के लिए जावा में cookie.setPath ("/")) हालांकि डिफ़ॉल्ट रूप से पथ खाली था। कुछ समय के लिए मैंने सोचा कि यह मुद्दा विशेष 'लोकलहोस्ट' डोमेन कुकी हैंडलिंग (http://stackoverflow.com/questions/1134290/cookies-on-localhost-with-explicit-domain) था लेकिन यह समस्या नहीं थी समाप्त। हो सकता है कि दूसरों के लिए पढ़ने के लायक हो। – jlpp

-1

यदि आपने फ़ाइल में डाउनलोड करने के विरोध में एक फ़ाइल डाउनलोड की है, जिसे सहेजा गया है, तो यह निर्धारित करने का कोई तरीका नहीं है कि डाउनलोड कब पूरा हो गया है, क्योंकि यह वर्तमान दस्तावेज़ के दायरे में नहीं है, बल्कि एक अलग प्रक्रिया है ब्राउज़र में

+8

मुझे स्पष्टीकरण देना चाहिए - मैं डाउनलोड * पूर्ण * के साथ बहुत चिंतित नहीं हूं। अगर मैं सिर्फ डाउनलोड शुरू होने पर पहचान सकता हूं, तो यह पर्याप्त होगा। –

3

उपयोगकर्ता फ़ाइल की पीढ़ी ट्रिगर होता है तो आप बस उस "डाउनलोड" के लिए एक अनूठा पहचान प्रदान करेगा, और हर कुछ सेकंड (AJAX के साथ या चेक) एक पृष्ठ ताज़ा करता है करने के लिए उपयोगकर्ता भेज सकते हैं। एक बार फ़ाइल समाप्त होने के बाद, इसे उसी अद्वितीय आईडी के तहत सहेजें और ...

  • यदि फ़ाइल तैयार है, तो डाउनलोड करें।
  • यदि फ़ाइल तैयार नहीं है, तो प्रगति दिखाएं।

फिर आप पूरे आईफ्रेम/प्रतीक्षा/ब्राउज़रविंडो गड़बड़ी को छोड़ सकते हैं, फिर भी वास्तव में एक शानदार समाधान है।

+0

यह ऊपर वर्णित अस्थायी-फ़ाइल दृष्टिकोण जैसा लगता है । अगर ऐसा लगता है कि मेरा विचार असंभव है, तो मैं ऐसा कुछ कर सकता हूं, लेकिन मैं इसे टालने की उम्मीद कर रहा था। –

2

यदि आप सर्वर पर फ़ाइल जेनरेट और स्टोर नहीं करना चाहते हैं, तो क्या आप स्थिति को स्टोर करने के इच्छुक हैं, उदा। फाइल-इन-प्रोग्रेस, फाइल-पूर्ण? आपका "प्रतीक्षा" पृष्ठ सर्वर को यह जानने के लिए मतदान कर सकता है कि फ़ाइल पीढ़ी कब पूर्ण हो जाती है। आप यह सुनिश्चित करने के लिए नहीं जानते कि ब्राउजर ने डाउनलोड शुरू किया है लेकिन आपको कुछ आत्मविश्वास होगा।

2

मुझे बस यही समस्या थी। मेरा समाधान अस्थायी फ़ाइलों का उपयोग करना था क्योंकि मैं पहले से ही अस्थायी फ़ाइलों का एक समूह उत्पन्न कर रहा था।फार्म के साथ प्रस्तुत किया जाता है:

var microBox = { 
    show : function(content) { 
     $(document.body).append('<div id="microBox_overlay"></div><div id="microBox_window"><div id="microBox_frame"><div id="microBox">' + 
     content + '</div></div></div>'); 
     return $('#microBox_overlay'); 
    }, 

    close : function() { 
     $('#microBox_overlay').remove(); 
     $('#microBox_window').remove(); 
    } 
}; 

$.fn.bgForm = function(content, callback) { 
    // Create an iframe as target of form submit 
    var id = 'bgForm' + (new Date().getTime()); 
    var $iframe = $('<iframe id="' + id + '" name="' + id + '" style="display: none;" src="about:blank"></iframe>') 
     .appendTo(document.body); 
    var $form = this; 
    // Submittal to an iframe target prevents page refresh 
    $form.attr('target', id); 
    // The first load event is called when about:blank is loaded 
    $iframe.one('load', function() { 
     // Attach listener to load events that occur after successful form submittal 
     $iframe.load(function() { 
      microBox.close(); 
      if (typeof(callback) == 'function') { 
       var iframe = $iframe[0]; 
       var doc = iframe.contentWindow.document; 
       var data = doc.body.innerHTML; 
       callback(data); 
      } 
     }); 
    }); 

    this.submit(function() { 
     microBox.show(content); 
    }); 

    return this; 
}; 

$('#myForm').bgForm('Please wait...'); 

स्क्रिप्ट है कि फाइल मेरे पास है उत्पन्न करता है के अंत में:

header('Refresh: 0;url=fetch.php?token=' . $token); 
echo '<html></html>'; 

यह आइफ्रेम पर लोड घटना का कारण होगा निकाल दिया जाए। फिर प्रतीक्षा संदेश बंद हो गया है और फ़ाइल डाउनलोड तब शुरू हो जाएगा। आईई 7 और फ़ायरफ़ॉक्स पर परीक्षण किया गया।

0

प्रश्न यह है कि फ़ाइल उत्पन्न होने के दौरान 'प्रतीक्षा' संकेतक होना चाहिए और फ़ाइल डाउनलोड होने के बाद सामान्य पर वापस जाना है। जिस तरह से मुझे यह पसंद है, वह एक छिपी आईफ्रेम का उपयोग कर रहा है और फ्रेम के अधिभार ईवेंट को हुक कर रहा है ताकि डाउनलोड शुरू होने पर मेरे पेज को पता चल सके। लेकिन ऑनलोड फ़ाइल डाउनलोड के लिए आईई में आग नहीं लगाता है (जैसे अटैचमेंट हेडर टोकन के साथ)। सर्वर को मतदान करना काम करता है, लेकिन मैं अतिरिक्त जटिलता को नापसंद करता हूं। तो यहां मैं क्या करता हूं:

  • छुपा आईफ्रेम सामान्य रूप से लक्षित करें।
  • सामग्री जेनरेट करें। इसे के साथ 2 मिनट में एक पूर्ण टाइमआउट के साथ कैश करें।
  • एक जावास्क्रिप्ट को कॉलिंग क्लाइंट पर रीडायरेक्ट भेजें, अनिवार्य रूप से जनरेटर पृष्ठ को दूसरी बार कॉल करना। नोट: इससे ओई में ऑनलोड ईवेंट आग लग जाएगी क्योंकि यह नियमित पृष्ठ की तरह काम कर रहा है।
  • कैश से सामग्री को हटाएं और इसे ग्राहक को भेजें।

अस्वीकरण, एक व्यस्त साइट पर ऐसा न करें, क्योंकि कैशिंग जोड़ सकता है। लेकिन वास्तव में, यदि आपकी साइटें जो लंबे समय तक चलने वाली प्रक्रिया में व्यस्त हैं, वैसे भी आपको धागे की भूख लगी होगी।

यहां कोडबींड जैसा दिखता है, जो आपको वास्तव में चाहिए।

public partial class Download : System.Web.UI.Page 
{ 
    protected System.Web.UI.HtmlControls.HtmlControl Body; 

    protected void Page_Load(object sender, EventArgs e) 
    { 
     byte[ ] data; 
     string reportKey = Session.SessionID + "_Report"; 

     // Check is this page request to generate the content 
     // or return the content (data query string defined) 
     if (Request.QueryString[ "data" ] != null) 
     { 
      // Get the data and remove the cache 
      data = Cache[ reportKey ] as byte[ ]; 
      Cache.Remove(reportKey); 

      if (data == null)      
       // send the user some information 
       Response.Write("Javascript to tell user there was a problem.");      
      else 
      { 
       Response.CacheControl = "no-cache"; 
       Response.AppendHeader("Pragma", "no-cache"); 
       Response.Buffer = true; 

       Response.AppendHeader("content-disposition", "attachment; filename=Report.pdf"); 
       Response.AppendHeader("content-size", data.Length.ToString()); 
       Response.BinaryWrite(data); 
      } 
      Response.End();     
     } 
     else 
     { 
      // Generate the data here. I am loading a file just for an example 
      using (System.IO.FileStream stream = new System.IO.FileStream(@"C:\1.pdf", System.IO.FileMode.Open)) 
       using (System.IO.BinaryReader reader = new System.IO.BinaryReader(stream)) 
       { 
        data = new byte[ reader.BaseStream.Length ]; 
        reader.Read(data, 0, data.Length); 
       } 

      // Store the content for retrieval    
      Cache.Insert(reportKey, data, null, DateTime.Now.AddMinutes(5), TimeSpan.Zero); 

      // This is the key bit that tells the frame to reload this page 
      // and start downloading the content. NOTE: Url has a query string 
      // value, so that the content isn't generated again. 
      Body.Attributes.Add("onload", "window.location = 'binary.aspx?data=t'"); 
     } 
    } 
11

वर्ष धागा, मुझे पता है ...

लेकिन उन है कि गूगल द्वारा यहाँ का नेतृत्व कर रहे हैं मेरी समाधान में रुचि हो सकती। यह बहुत आसान है, फिर भी विश्वसनीय है। और यह वास्तविक प्रगति संदेशों को प्रदर्शित करना संभव बनाता है (और आसानी से मौजूदा प्रक्रियाओं में प्लग इन किया जा सकता है):

ऐसी स्क्रिप्ट जो प्रक्रिया करती है (मेरी समस्या थी: http के माध्यम से फ़ाइलों को पुनर्प्राप्त करना और उन्हें ज़िप के रूप में वितरित करना) की स्थिति लिखती है सत्र।

स्थिति मतदान और हर सेकेंड प्रदर्शित किया जाता है। यह सब ठीक है (ठीक है, इसकी नहीं। आपको बहुत सारे विवरणों का ख्याल रखना है [उदाहरण के लिए समवर्ती डाउनलोड], लेकिन यह शुरू करने के लिए एक अच्छी जगह है ;-))।

downloadpage:

<a href="download.php?id=1" class="download">DOWNLOAD 1</a> 
    <a href="download.php?id=2" class="download">DOWNLOAD 2</a> 
    ... 
    <div id="wait"> 
    Please wait... 
    <div id="statusmessage"></div> 
    </div> 
    <script> 
//this is jquery 
    $('a.download').each(function() 
     { 
     $(this).click(
      function(){ 
       $('#statusmessage').html('prepare loading...'); 
       $('#wait').show(); 
       setTimeout('getstatus()', 1000); 
      } 
     ); 
     }); 
    }); 
    function getstatus(){ 
     $.ajax({ 
      url: "/getstatus.php", 
      type: "POST", 
      dataType: 'json', 
      success: function(data) { 
      $('#statusmessage').html(data.message); 
      if(data.status=="pending") 
       setTimeout('getstatus()', 1000); 
      else 
       $('#wait').hide(); 
      } 
     }); 
    } 
    </script> 

getstatus.php

<?php 
session_start(); 
echo json_encode($_SESSION['downloadstatus']); 
?> 

download.php

<?php 
    session_start(); 
    $processing=true; 
    while($processing){ 
     $_SESSION['downloadstatus']=array("status"=>"pending","message"=>"Processing".$someinfo); 
     session_write_close(); 
     $processing=do_what_has_2Bdone(); 
     session_start(); 
    } 
     $_SESSION['downloadstatus']=array("status"=>"finished","message"=>"Done"); 
//and spit the generated file to the browser 
    ?> 
+3

लेकिन यदि उपयोगकर्ता के पास कई खिड़कियां या डाउनलोड खुले हैं? तो आप यहां सर्वर पर एक अनावश्यक कॉल प्राप्त करते हैं – Yuki

+0

यदि आपके पास है एक उपयोगकर्ता से कई कनेक्शन वे सभी कनेक्शन समाप्त होने की प्रतीक्षा कर रहे हैं क्योंकि session_start() उपयोगकर्ता के लिए सत्र लॉक करता है और अन्य सभी प्रक्रियाओं को इसे एक्सेस करने से रोकता है। –

+1

आपको ईवेंट पंजीकरण के लिए '.each()' का उपयोग करने की आवश्यकता नहीं है। बस '$ (' a.download ') कहें। क्लिक करें() ' – robisrob

26

एक बहुत ही सरल (और लंगड़ा) एक लाइन तो लोडिंग संवाद बंद करने के लिए window.onblur() ईवेंट का उपयोग करना है। बेशक, यदि यह बहुत लंबा लगता है और उपयोगकर्ता कुछ और करने का फैसला करता है (जैसे ईमेल पढ़ना) लोडिंग संवाद बंद हो जाएगा।

+0

यह एक साधारण दृष्टिकोण है जो फ़ाइल डाउनलोड के लिए लोडिंग ओवरले से छुटकारा पाने के लिए आदर्श है जिसे 'onbeforeunload' का उपयोग करके ट्रिगर किया गया था धन्यवाद। – wf4

+4

यह सभी ब्राउज़रों में काम नहीं करता है (कुछ डाउनलोड वर्कफ़्लो के हिस्से के रूप में वर्तमान विंडो को नहीं छोड़ते/धुंधला नहीं करते हैं, उदाहरण के लिए सफारी, कुछ आईई संस्करण आदि)। – hiattp

+0

क्रोम और अन्य ऐसे ब्राउज़र उन फ़ाइलों को स्वतः डाउनलोड करते हैं जहां यह स्थिति विफल हो जाएगी। – Lucky

11

मैं ब्लॉब्स डाउनलोड करने और डाउनलोड के बाद ऑब्जेक्ट-यूआरएल को निरस्त करने के लिए निम्नलिखित का उपयोग करता हूं। यह क्रोम और फ़ायरफ़ॉक्स में काम करता है!

function download(blob){ 
    var url = URL.createObjectURL(blob); 
    console.log('create ' + url); 

    window.addEventListener('focus', window_focus, false); 
    function window_focus(){ 
     window.removeEventListener('focus', window_focus, false);     
     URL.revokeObjectURL(url); 
     console.log('revoke ' + url); 
    } 
    location.href = url; 
} 

फ़ाइल डाउनलोड संवाद बंद होने के बाद, विंडो उसे फोकस कर देती है ताकि फोकस ईवेंट ट्रिगर हो।

+0

के बाहर कोई भी कार्रवाई अभी भी विंडो स्विच करने का मुद्दा है और जो वापस करेगा मोडल छुपाने का कारण बनता है। – dudeNumber4

+3

क्रोम जैसे ब्राउज़र जो नीचे ट्रे में डाउनलोड करते हैं, वे कभी भी विंडो को धुंधला/दोबारा नहीं दबाते हैं। – Coleman

-2

बटन/लिंक क्लिक होने पर और इसे शरीर में जोड़कर एक आईफ्रेम बनाएं।

    $('<iframe />') 
       .attr('src', url) 
       .attr('id','iframe_download_report') 
       .hide() 
       .appendTo('body'); 

देरी के साथ एक आईफ्रेम बनाएं और डाउनलोड के बाद इसे हटा दें।

      var triggerDelay = 100; 
          var cleaningDelay = 20000; 
          var that = this; 
          setTimeout(function() { 
           var frame = $('<iframe style="width:1px; height:1px;" class="multi-download-frame"></iframe>'); 
           frame.attr('src', url+"?"+ "Content-Disposition: attachment ; filename="+that.model.get('fileName')); 
           $(ev.target).after(frame); 
           setTimeout(function() { 
            frame.remove(); 
           }, cleaningDelay); 
          }, triggerDelay); 
+0

इसमें जानकारी की कमी है और यह "लोडिंग को छिपाने के लिए" समस्या का समाधान नहीं करता है। –

3

एल्मर के उदाहरण के आधार पर मैंने अपना स्वयं का समाधान तैयार किया है। तत्वों के बाद परिभाषित डाउनलोड कक्षा के साथ क्लिक करें, यह स्क्रीन पर कस्टम संदेश दिखाने देता है। मैंने फोकस संदेश को छिपाने के लिए ट्रिगर किया है।

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

$(function(){$('.download').click(function() { ShowDownloadMessage(); }); }) 

function ShowDownloadMessage() 
{ 
    $('#message-text').text('your report is creating, please wait...'); 
    $('#message').show(); 
    window.addEventListener('focus', HideDownloadMessage, false); 
} 

function HideDownloadMessage(){ 
    window.removeEventListener('focus', HideDownloadMessage, false);     
    $('#message').hide(); 
} 

एचटीएमएल

<div id="message" style="display: none"> 
    <div id="message-screen-mask" class="ui-widget-overlay ui-front"></div> 
    <div id="message-text" class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-front ui-draggable ui-resizable waitmessage">please wait...</div> 
</div> 

अब आप डाउनलोड करने के लिए किसी भी तत्व को लागू करना चाहिए:

<a class="download" href="file://www.ocelot.com.pl/prepare-report">Download report</a> 

या

<input class="download" type="submit" value="Download" name="actionType"> 

प्रत्येक डाउनलोड करने के बाद क्लिक आप संदेश अपनी रिपोर्ट पैदा कर रही है, कृपया प्रतीक्षा करें देखेंगे ...

+0

यदि उपयोगकर्ता विंडो पर क्लिक करता है तो क्या होगा? –

3

मैं पार्टी के लिए बहुत देर हो रही है, लेकिन मैं अगर कोई यहाँ इस डाल देता हूँ अन्यथा मेरा समाधान जानना चाहेंगे:

मुझे इस सटीक समस्या के साथ एक वास्तविक संघर्ष था, लेकिन मुझे iframes का उपयोग करके एक व्यवहार्य समाधान मिला (मुझे पता है, मुझे पता है। यह भयानक है लेकिन यह मेरे पास एक साधारण समस्या के लिए काम करता है)

मेरे पास एक HTML पृष्ठ था जिसने एक अलग PHP स्क्रिप्ट लॉन्च की जिसने फ़ाइल उत्पन्न की और फिर इसे डाउनलोड किया। एचटीएमएल पृष्ठ पर, मैं HTML शीर्षक में निम्नलिखित jQuery का इस्तेमाल किया (यदि आप एक jQuery पुस्तकालय के रूप में अच्छी तरह से शामिल करना होगा):,

<script> 
    $(function(){ 
     var iframe = $("<iframe>", {name: 'iframe', id: 'iframe',}).appendTo("body").hide(); 
     $('#click').on('click', function(){ 
      $('#iframe').attr('src', 'your_download_script.php'); 
     }); 
     $('iframe').load(function(){ 
      $('#iframe').attr('src', 'your_download_script.php?download=yes'); <!--on first iframe load, run script again but download file instead--> 
      $('#iframe').unbind(); <!--unbinds the iframe. Helps prevent against infinite recursion if the script returns valid html (such as echoing out exceptions) --> 
     }); 
    }); 
</script> 

your_download_script.php पर निम्नलिखित हैं:

function downloadFile($file_path) { 
    if (file_exists($file_path)) { 
     header('Content-Description: File Transfer'); 
     header('Content-Type: text/csv'); 
     header('Content-Disposition: attachment; filename=' . basename($file_path)); 
     header('Expires: 0'); 
     header('Cache-Control: must-revalidate'); 
     header('Pragma: public'); 
     header('Content-Length: ' . filesize($file_path)); 
     ob_clean(); 
     flush(); 
     readfile($file_path); 
     exit(); 
    } 
} 


$_SESSION['your_file'] = path_to_file; //this is just how I chose to store the filepath 

if (isset($_REQUEST['download']) && $_REQUEST['download'] == 'yes') { 
    downloadFile($_SESSION['your_file']); 
} else { 
    *execute logic to create the file* 
} 

इसे तोड़ने के लिए, jquery ने पहली बार अपनी php स्क्रिप्ट को iframe में लॉन्च किया है। फाइल उत्पन्न होने के बाद आईफ्रेम लोड हो जाता है। फिर jquery स्क्रिप्ट को फ़ाइल डाउनलोड करने के लिए स्क्रिप्ट को एक अनुरोध चर के साथ फिर से लॉन्च करता है।

कारण यह है कि आप डाउनलोड और फ़ाइल पीढ़ी को एक ही बार में नहीं कर सकते हैं, php header() फ़ंक्शन के कारण है। यदि आप हेडर() का उपयोग करते हैं, तो आप स्क्रिप्ट को किसी वेब पेज के अलावा किसी अन्य चीज़ में बदल रहे हैं और jquery कभी भी डाउनलोड स्क्रिप्ट को 'लोड' होने के रूप में नहीं पहचान पाएगा। मुझे पता है कि जब ब्राउज़र को फ़ाइल प्राप्त होती है तो यह पता लगाना आवश्यक नहीं है लेकिन आपकी समस्या मेरे जैसा ही लगती है।

5

मैंने एक साधारण जावास्क्रिप्ट क्लास लिखा है जो बुलटोरियस answer में वर्णित एक जैसी तकनीक को लागू करता है। मुझे उम्मीद है कि यह किसी के लिए उपयोगी हो सकता है। GitHub परियोजना response-monitor.js

कहा जाता है डिफ़ॉल्ट रूप से यह प्रतीक्षा संकेतक के रूप में spin.js का उपयोग करता है लेकिन यह भी एक कस्टम सूचक के कार्यान्वयन के लिए कॉलबैक का एक सेट प्रदान करता है।

JQuery समर्थित है लेकिन आवश्यक नहीं है।

ध्यान देने योग्य सुविधाओं

  • सरल एकीकरण
  • कोई निर्भरता
  • JQuery प्लग में (वैकल्पिक)
  • स्पिन।js एकता (वैकल्पिक)
  • निगरानी की घटनाओं के लिए विन्यास कॉलबैक
  • एकाधिक अनुरोध
  • सर्वर साइड त्रुटि का पता लगाने
  • समय समाप्ति का पता लगाने
  • क्रॉस ब्राउज़र

उदाहरण उपयोग

हैंडल

एचटीएमएल

<!-- the response monitor implementation --> 
<script src="response-monitor.js"></script> 

<!-- optional JQuery plug-in --> 
<script src="response-monitor.jquery.js"></script> 

<a class="my_anchors" href="/report?criteria1=a&criteria2=b#30">Link 1 (Timeout: 30s)</a> 
<a class="my_anchors" href="/report?criteria1=b&criteria2=d#10">Link 2 (Timeout: 10s)</a> 

<form id="my_form" method="POST"> 
    <input type="text" name="criteria1"> 
    <input type="text" name="criteria2"> 
    <input type="submit" value="Download Report"> 
</form> 

क्लाइंट (सादा जावास्क्रिप्ट)

//registering multiple anchors at once 
var my_anchors = document.getElementsByClassName('my_anchors'); 
ResponseMonitor.register(my_anchors); //clicking on the links initiates monitoring 

//registering a single form 
var my_form = document.getElementById('my_form'); 
ResponseMonitor.register(my_form); //the submit event will be intercepted and monitored 

क्लाइंट (JQuery) कॉलबैक (JQuery)

//when options are defined, the default spin.js integration is bypassed 
var options = { 
    onRequest: function(token){ 
     $('#cookie').html(token); 
     $('#outcome').html(''); 
     $('#duration').html(''); 
    }, 
    onMonitor: function(countdown){ 
     $('#duration').html(countdown); 
    }, 
    onResponse: function(status){ 
     $('#outcome').html(status==1?'success':'failure'); 
    }, 
    onTimeout: function(){ 
     $('#outcome').html('timeout'); 
    } 
}; 

//monitor all anchors in the document 
$('a').ResponseMonitor(options); 

सर्वर (PHP)

साथ

$('.my_anchors').ResponseMonitor(); 
$('#my_form').ResponseMonitor({timeout: 20}); 

क्लाइंट

$cookiePrefix = 'response-monitor'; //must match the one set on the client options 
$tokenValue = $_GET[$cookiePrefix]; 
$cookieName = $cookiePrefix.'_'.$tokenValue; //ex: response-monitor_1419642741528 

//this value is passed to the client through the ResponseMonitor.onResponse callback 
$cookieValue = 1; //for ex, "1" can interpret as success and "0" as failure 

setcookie(
    $cookieName, 
    $cookieValue, 
    time()+300,   // expire in 5 minutes 
    "/", 
    $_SERVER["HTTP_HOST"], 
    true, 
    false 
); 

header('Content-Type: text/plain'); 
header("Content-Disposition: attachment; filename=\"Response.txt\""); 

sleep(5); //simulate whatever delays the response 
print_r($_REQUEST); //dump the request in the text file 

अधिक उदाहरण के लिए भंडार पर examples फ़ोल्डर की जांच करें।

2

आप एक फ़ाइल है कि आप गतिशील रूप से जेनरेट कर रहे हैं स्ट्रीमिंग कर रहे हैं, और यह भी एक वास्तविक समय सर्वर से ग्राहक मैसेजिंग पुस्तकालय लागू किया है, तो आप बहुत आसानी से अपने ग्राहक को सचेत कर सकते हैं।

सर्वर-टू-क्लाइंट मैसेजिंग लाइब्रेरी मुझे पसंद है और अनुशंसा है Socket.io (Node.js के माध्यम से)। आपकी सर्वर स्क्रिप्ट के बाद उस स्क्रिप्ट में आपकी आखिरी पंक्ति डाउनलोड करने के लिए स्ट्रीम की जा रही फ़ाइल उत्पन्न करने के बाद सॉकेट.io को एक संदेश उत्सर्जित कर सकता है जो क्लाइंट को अधिसूचना भेजता है। क्लाइंट पर, सॉकेट.ओ सर्वर से उत्सर्जित आने वाले संदेशों के लिए सुनता है और आपको उन पर कार्य करने की अनुमति देता है। दूसरों पर इस विधि का उपयोग करने का लाभ यह है कि स्ट्रीमिंग के बाद आप "सत्य" खत्म घटना का पता लगाने में सक्षम हैं।

उदाहरण के लिए, आप डाउनलोड लिंक के बाद अपना व्यस्त संकेतक दिखा सकते हैं, अपनी फ़ाइल स्ट्रीम कर सकते हैं, अपनी स्ट्रीमिंग स्क्रिप्ट की अंतिम पंक्ति में सर्वर से Socket.io को एक संदेश उत्सर्जित कर सकते हैं, क्लाइंट को अधिसूचना के लिए सुन सकते हैं , अधिसूचना प्राप्त करें और व्यस्त संकेतक को छुपाकर अपना यूआई अपडेट करें।

मुझे एहसास है कि इस प्रश्न के उत्तर पढ़ने वाले अधिकांश लोगों के पास इस प्रकार का सेटअप नहीं हो सकता है, लेकिन मैंने अपनी खुद की परियोजनाओं में इस प्रभाव का सही प्रभाव डाला है और यह आश्चर्यजनक रूप से काम करता है।

सॉकेट.ओओ स्थापित करने और उपयोग करने के लिए अविश्वसनीय रूप से आसान है। और देखें: http://socket.io/

0

यदि आप डाउनलोड संवाद प्रदर्शित होने तक केवल एक संदेश या लोडर gif प्रदर्शित करना चाहते हैं तो त्वरित समाधान संदेश को एक छिपे हुए कंटेनर में रखना है और जब आप उस फ़ाइल पर क्लिक करते हैं जो फ़ाइल उत्पन्न करता है डाउनलोड किया जा सकता है आप कंटेनर दृश्यमान बनाते हैं। फिर संदेश

0

युक्त कंटेनर को छिपाने के लिए बटन की फोकसआउट घटना को पकड़ने के लिए jquery या जावास्क्रिप्ट का उपयोग करें यदि ब्लॉब के साथ Xmlhttprequest कोई विकल्प नहीं है तो आप अपनी फ़ाइल को नई विंडो में खोल सकते हैं और जांच सकते हैं कि एनई तत्वों में आबादी हो रही है या नहीं अंतराल के साथ खिड़की शरीर।

var form = document.getElementById("frmDownlaod"); 
 
form.setAttribute("action","downoad/url"); 
 
form.setAttribute("target","downlaod"); 
 
var exportwindow = window.open("", "downlaod", "width=800,height=600,resizable=yes"); 
 
form.submit(); 
 

 
var responseInterval = setInterval(function(){ 
 
\t var winBody = exportwindow.document.body 
 
\t if(winBody.hasChildNodes()) // or 'downoad/url' === exportwindow.document.location.href 
 
\t { 
 
\t \t clearInterval(responseInterval); 
 
\t \t // do your work 
 
\t \t // if there is error page configured your application for failed requests, check for those dom elemets 
 
\t } 
 
}, 1000) 
 
//Better if you specify maximun no of intervals

संबंधित मुद्दे