javascript - जब ब्राउज़र को फ़ाइल डाउनलोड प्राप्त होता है तो पता लगाएं




http mime (11)

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

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

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

मैंने कोशिश की एक दृष्टिकोण एक बहु-पक्ष प्रतिक्रिया का उपयोग कर रहा है। तो यह एक खाली 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 फ़ाइल प्राप्त करता है, "लोड" ईवेंट को सक्रिय करता है, फिर डाउनलोड करने योग्य फ़ाइल के लिए "सहेजें" संवाद दिखाता है। लेकिन यह आईई और सफारी पर विफल रहता है; आईई "लोड" घटना को निकालता है लेकिन फ़ाइल डाउनलोड नहीं करता है, और सफारी फ़ाइल डाउनलोड करता है (गलत नाम और सामग्री-प्रकार के साथ), और "लोड" ईवेंट को आग नहीं करता है।

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

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


एक संभावित समाधान क्लाइंट पर जावास्क्रिप्ट का उपयोग करता है।

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

  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://.com/a/1459794/59087
    // See: http://shiflett.org/blog/2006/mar/server-name-versus-http-host
    // See: http://.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
    );
}

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


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

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

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


पुराना धागा, मुझे पता है ...

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

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

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

डाउनलोड पेज:

    <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
    ?>

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

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 और फ़ायरफ़ॉक्स पर परीक्षण किया गया।


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

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

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


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

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

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

उल्लेखनीय विशेषताएं

  • सरल एकीकरण
  • कोई निर्भरता नहीं
  • JQuery प्लग-इन (वैकल्पिक)
  • Spin.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)

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

कॉलबैक के साथ ग्राहक (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)

$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 फ़ोल्डर की जांच करें।


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

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

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

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

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


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


यदि ब्लॉब के साथ 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(){
	var winBody = exportwindow.document.body
	if(winBody.hasChildNodes()) // or 'downoad/url' === exportwindow.document.location.href
	{
		clearInterval(responseInterval);
		// do your work
		// if there is error page configured your application for failed requests, check for those dom elemets 
	}
}, 1000)
//Better if you specify maximun no of intervals


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

  • सामान्य रूप से छुपा IFrame को लक्षित करें।
  • सामग्री उत्पन्न करें। इसे 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'");
        }
    }




mime