JSON डेटा के साथ POST के माध्यम से फ़ाइल डाउनलोड करने के लिए जावास्क्रिप्ट / jQuery


250

मेरे पास एक jquery- आधारित सिंगल-पेज वेबप है। यह AJAX कॉल के माध्यम से एक RESTful वेब सेवा के साथ संचार करता है।

मैं निम्नलिखित को पूरा करने की कोशिश कर रहा हूं:

  1. एक POST जमा करें जिसमें JSON डेटा एक REST url में हो।
  2. यदि अनुरोध JSON प्रतिक्रिया निर्दिष्ट करता है, तो JSON वापस आ जाता है।
  3. यदि अनुरोध एक पीडीएफ / एक्सएलएस / आदि प्रतिक्रिया निर्दिष्ट करता है, तो एक डाउनलोड करने योग्य बाइनरी वापस आ जाती है।

मेरे पास अभी 1 & 2 काम कर रहे हैं, और क्लाइंट jquery ऐप वेब पेज में दिए गए डेटा को JSON डेटा के आधार पर DOM तत्व बनाकर प्रदर्शित करता है। मेरे पास वेब-सेवा की दृष्टि से # 3 काम है, जिसका अर्थ है कि अगर JSON पैरामीटर दिए गए हैं तो यह एक बाइनरी फ़ाइल बनाएगा और लौटाएगा। लेकिन मैं क्लाइंट जावास्क्रिप्ट कोड में # 3 से निपटने का सबसे अच्छा तरीका अनिश्चित हूं।

क्या इस तरह से अजाक्स कॉल से एक डाउनलोड करने योग्य फ़ाइल वापस प्राप्त करना संभव है? मुझे फ़ाइल डाउनलोड करने और सहेजने के लिए ब्राउज़र कैसे मिलेगा?

$.ajax({
    type: "POST",
    url: "/services/test",
    contentType: "application/json",
    data: JSON.stringify({category: 42, sort: 3, type: "pdf"}),
    dataType: "json",
    success: function(json, status){
        if (status != "success") {
            log("Error loading data");
            return;
        }
        log("Data loaded!");
    },
    error: function(result, status, err) {
        log("Error loading data");
        return;
    }
});

सर्वर निम्नलिखित हेडर के साथ प्रतिक्रिया करता है:

Content-Disposition:attachment; filename=export-1282022272283.pdf
Content-Length:5120
Content-Type:application/pdf
Server:Jetty(6.1.11)

एक अन्य विचार यह है कि पीडीएफ को जेनरेट किया जाए और इसे सर्वर पर स्टोर किया जाए और JSON को लौटाया जाए जिसमें फ़ाइल का URL शामिल है। फिर, अजाक्स सफलता हैंडलर में एक और कॉल जारी करने के लिए निम्न जैसा कुछ करें:

success: function(json,status) {
    window.location.href = json.url;
}

लेकिन इसका मतलब है कि मुझे सर्वर पर एक से अधिक कॉल करने की आवश्यकता होगी, और मेरे सर्वर को डाउनलोड करने योग्य फ़ाइलों का निर्माण करने, उन्हें कहीं स्टोर करने की आवश्यकता होगी, फिर समय-समय पर उस भंडारण क्षेत्र को साफ करना होगा।

इसे पूरा करने का एक सरल तरीका होना चाहिए। विचार?


संपादित करें: $ .ajax के लिए डॉक्स की समीक्षा करने के बाद, मैं देखता हूं कि प्रतिक्रिया डेटाटाइप केवल एक में से एक हो सकता है xml, html, script, json, jsonp, text, इसलिए मैं अनुमान लगा रहा हूं कि जब तक मैं द्विआधारी फ़ाइल का उपयोग नहीं करता, तब तक किसी ऐजैक्स अनुरोध का उपयोग करके सीधे फ़ाइल डाउनलोड करने का कोई तरीका नहीं है। डेटा यूआरआई योजना जैसा कि @VinayC उत्तर में सुझाव दिया गया है (जो कुछ ऐसा नहीं है जो मैं करना चाहता हूं)।

इसलिए मुझे लगता है कि मेरे विकल्प हैं:

  1. Ajax का उपयोग न करें और इसके बजाय एक फॉर्म पोस्ट सबमिट करें और मेरे JSON डेटा को फॉर्म वैल्यू में एम्बेड करें। शायद छिपे हुए iframes और इस तरह के साथ गड़बड़ करने की आवश्यकता होगी।

  2. अजाक्स का उपयोग न करें और इसके बजाय एक मानक GET अनुरोध बनाने और इस URL के लिए window.location.href सेट करने के लिए मेरे JSON डेटा को क्वेरी स्ट्रिंग में परिवर्तित करें। ब्राउज़र को एप्लिकेशन URL से बदलने से रोकने के लिए मेरे क्लिक हैंडलर में event.preventDefault () का उपयोग करने की आवश्यकता हो सकती है।

  3. ऊपर मेरे अन्य विचार का उपयोग करें, लेकिन @naikus उत्तर से सुझावों के साथ बढ़ाया। AJAX अनुरोध को कुछ पैरामीटर के साथ सबमिट करें जो वेब-सेवा को यह बताता है कि इसे अजाक्स कॉल के माध्यम से बुलाया जा रहा है। यदि वेब सेवा को अजाक्स कॉल से कॉल किया जाता है, तो जेनसन को जनरेट किए गए संसाधन के साथ URL पर लौटाएं। यदि संसाधन को सीधे कहा जाता है, तो वास्तविक बाइनरी फ़ाइल लौटाएं।

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

इसे पूरा करने का कोई और तरीका? इन विधियों के बारे में कोई भी नियम / सहमति जो मुझे पता होनी चाहिए?


संभव फ़ाइल
IsmailS

6
यह एक "थोड़ा सा" पहले था, इसलिए यह एक नकल कैसे है
GiM

1
url = 'http://localhost/file.php?file='+ $('input').val(); window.open(url); समान परिणाम प्राप्त करने का आसान तरीका। हैडर को php फाइल में रखें। कोई भी अजाक्स भेजने या अनुरोध प्राप्त करने की आवश्यकता नहीं है
अभिषेक बैगुल 18

जवाबों:


171

letronje का समाधान केवल बहुत ही सरल पृष्ठों के लिए काम करता है। document.body.innerHTML +=शरीर का HTML पाठ लेता है, iframe HTML को जोड़ता है, और पृष्ठ के आंतरिक HTML को उस स्ट्रिंग में सेट करता है। यह किसी भी घटना को आपके पेज के साथ अन्य चीजों के अलावा, मिटा देगा। एक तत्व बनाएं और appendChildइसके बजाय उपयोग करें ।

$.post('/create_binary_file.php', postData, function(retData) {
  var iframe = document.createElement("iframe");
  iframe.setAttribute("src", retData.url);
  iframe.setAttribute("style", "display: none");
  document.body.appendChild(iframe);
}); 

या jQuery का उपयोग कर

$.post('/create_binary_file.php', postData, function(retData) {
  $("body").append("<iframe src='" + retData.url+ "' style='display: none;' ></iframe>");
}); 

यह वास्तव में क्या करता है: चर पोस्टडेटा में डेटा के साथ /create_binary_file.php पोस्ट करें; यदि वह पोस्ट सफलतापूर्वक पूर्ण हो जाती है, तो पृष्ठ के मुख्य भाग में एक नया iframe जोड़ें। धारणा यह है कि /create_binary_file.php की प्रतिक्रिया में एक मान 'url' शामिल होगा, जो कि URL है जो उत्पन्न पीडीएफ / XLS / etc फ़ाइल से डाउनलोड किया जा सकता है। उस पृष्ठ पर एक iframe जोड़ना जो उस URL का संदर्भ देता है जिसके परिणामस्वरूप ब्राउज़र फ़ाइल को डाउनलोड करने के लिए उपयोगकर्ता को बढ़ावा देगा, यह मानते हुए कि वेब सर्वर में उपयुक्त माइम प्रकार कॉन्फ़िगरेशन है।


1
मैं सहमत हूं, यह उपयोग करने से बेहतर है +=और मैं अपने आवेदन को तदनुसार अपडेट करूंगा। धन्यवाद!
टॉरेन

3
मुझे यह अवधारणा पसंद है, हालांकि क्रोम में कंसोल में यह संदेश है Resource interpreted as Document but transferred with MIME type application/pdf:। फिर यह मुझे चेतावनी भी देता है कि फ़ाइल खतरनाक हो सकती है। अगर मैं सीधे retData.url पर जाऊं, तो कोई चेतावनी या समस्या नहीं।
माइकल इरे

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

1
@ टॉरन: यदि आप सहमत हैं कि यह एक बेहतर उत्तर है, तो ध्यान दें कि आप किसी भी समय स्वीकार किए गए उत्तर को स्विच कर सकते हैं - या यहां तक ​​कि स्वीकृत चिह्न को पूरी तरह से हटा सकते हैं। बस नए उत्तर की जांच करें और स्वीकार किए गए चिह्न को स्थानांतरित कर दिया जाएगा। (ओल्ड सवाल है, लेकिन हाल ही में झंडे में लाया गया था।)
BoltClock

5
क्या है retData.url होने का अनुमान है?
मार्क थिएन

48

मैं एक और विकल्प के साथ खेल रहा हूं जो ब्लॉब्स का उपयोग करता है। मैं इसे पाठ दस्तावेज़ डाउनलोड करने में कामयाब रहा हूं, और मैंने पीडीएफ डाउनलोड किया है (हालांकि वे दूषित हैं)।

बूँद एपीआई का उपयोग करके आप निम्नलिखित कार्य कर सकेंगे:

$.post(/*...*/,function (result)
{
    var blob=new Blob([result]);
    var link=document.createElement('a');
    link.href=window.URL.createObjectURL(blob);
    link.download="myFileName.txt";
    link.click();

});

यह IE 10+, Chrome 8+, FF 4+ है। Https://developer.mozilla.org/en-US/docs/Web/API/URL.createOjectingL देखें

यह केवल क्रोम, फ़ायरफ़ॉक्स और ओपेरा में फ़ाइल डाउनलोड करेगा। यह ब्राउज़र को डाउनलोड करने के लिए मजबूर करने के लिए एंकर टैग पर एक डाउनलोड विशेषता का उपयोग करता है।


1
IE और सफारी पर डाउनलोड विशेषता का कोई समर्थन नहीं :( ( caniuse.com/#feat=download )। आप एक नई विंडो खोल सकते हैं और वहां सामग्री डाल सकते हैं, लेकिन पीडीएफ या एक्सेल के बारे में निश्चित नहीं ...
Marçal Juan

1
आपको कॉल करने के बाद ब्राउज़र मेमोरी को खाली करना चाहिए click:window.URL.revokeObjectURL(link.href);
एडवर्ड ब्रे

@ जोशबर्के यह पुराना है लेकिन यह मेरे अंत में काम करता है। मैं अपने ब्राउज़र को सहेजने के बजाय सहेजने के लिए तुरंत अपनी निर्देशिका को खोलने के लिए कैसे प्राप्त कर सकता हूं? आने वाली फ़ाइल का नाम निर्धारित करने का एक तरीका भी है?
जो

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

2
PDF के साथ यहां उपयोग की गई जानकारी को दूषित न करने के लिए mimetypes का
Mibo Tibaquira

18

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

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

इसमें थोड़ा और अधिक काम शामिल है, और शायद थोड़ा और अधिक प्रसंस्करण है, लेकिन कुल मिलाकर, मैंने इस समाधान के साथ बहुत बेहतर महसूस किया।

कोड C # / MVC में है

    public JsonResult Validate(int reportId, string format, ReportParamModel[] parameters)
    {
        // TODO: do validation

        if (valid)
        {
            GenerateParams generateParams = new GenerateParams(reportId, format, parameters);

            string data = new EntityBase64Converter<GenerateParams>().ToBase64(generateParams);

            return Json(new { State = "Success", Data = data });
        }

        return Json(new { State = "Error", Data = "Error message" });
    }

    public ActionResult Generate(string data)
    {
        GenerateParams generateParams = new EntityBase64Converter<GenerateParams>().ToEntity(data);

        // TODO: Generate file

        return File(bytes, mimeType);
    }

ग्राहक पर

    function generate(reportId, format, parameters)
    {
        var data = {
            reportId: reportId,
            format: format,
            params: params
        };

        $.ajax(
        {
            url: "/Validate",
            type: 'POST',
            data: JSON.stringify(data),
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            success: generateComplete
        });
    }

    function generateComplete(result)
    {
        if (result.State == "Success")
        {
            // this could/should already be set in the HTML
            formGenerate.action = "/Generate";
            formGenerate.target = iframeFile;

            hidData = result.Data;
            formGenerate.submit();
        }
        else
            // TODO: display error messages
    }

1
मुझे इस समाधान पर अच्छी नज़र नहीं है, लेकिन यह ध्यान देने योग्य है कि create_binary_file.php का उपयोग करके समाधान के बारे में कुछ भी नहीं है कि फ़ाइलों को डिस्क में सहेजने की आवश्यकता है। यह पूरी तरह से संभव होगा कि create_binary_file.php मेमोरी में बाइनरी फाइलें उत्पन्न करें।
सैमस्टीफेंस

11

एक सरल तरीका है, एक फॉर्म बनाएं और इसे पोस्ट करें, यह पृष्ठ को रीसेट करने का जोखिम चलाता है यदि रिटर्न माइम प्रकार कुछ ऐसा है जो एक ब्राउज़र खुल जाएगा, लेकिन सीएसवी के लिए और इस तरह यह एकदम सही है

उदाहरण के लिए अंडरस्कोर और jquery की आवश्यकता होती है

var postData = {
    filename:filename,
    filecontent:filecontent
};
var fakeFormHtmlFragment = "<form style='display: none;' method='POST' action='"+SAVEAS_PHP_MODE_URL+"'>";
_.each(postData, function(postValue, postKey){
    var escapedKey = postKey.replace("\\", "\\\\").replace("'", "\'");
    var escapedValue = postValue.replace("\\", "\\\\").replace("'", "\'");
    fakeFormHtmlFragment += "<input type='hidden' name='"+escapedKey+"' value='"+escapedValue+"'>";
});
fakeFormHtmlFragment += "</form>";
$fakeFormDom = $(fakeFormHtmlFragment);
$("body").append($fakeFormDom);
$fakeFormDom.submit();

Html, टेक्स्ट और इस तरह की चीजों के लिए, सुनिश्चित करें कि mimetype एप्लिकेशन / ऑक्टेट-स्ट्रीम जैसी कुछ चीज़ है

php कोड

<?php
/**
 * get HTTP POST variable which is a string ?foo=bar
 * @param string $param
 * @param bool $required
 * @return string
 */
function getHTTPPostString ($param, $required = false) {
    if(!isset($_POST[$param])) {
        if($required) {
            echo "required POST param '$param' missing";
            exit 1;
        } else {
            return "";
        }
    }
    return trim($_POST[$param]);
}

$filename = getHTTPPostString("filename", true);
$filecontent = getHTTPPostString("filecontent", true);

header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$filename\"");
echo $filecontent;

8

संक्षेप में, कोई सरल तरीका नहीं है। पीडीएफ फाइल दिखाने के लिए आपको एक और सर्वर अनुरोध करना होगा। अल हालांकि, कुछ विकल्प हैं, लेकिन वे सही नहीं हैं और सभी ब्राउज़रों पर काम नहीं करेंगे:

  1. को देखो डेटा URI योजना । यदि बाइनरी डेटा छोटा है, तो आप संभवतः URI में विंडो पासिंग डेटा को खोलने के लिए जावास्क्रिप्ट का उपयोग कर सकते हैं।
  2. स्थानीय फ़ाइल सिस्टम पर डेटा को बचाने और इसे वहां से खोलने के लिए Windows / IE का एकमात्र समाधान .NET कंट्रोल या FileSystemObject होगा।

धन्यवाद, मुझे डेटा यूआरआई योजना की जानकारी नहीं थी। ऐसा लगता है कि यह एक ही अनुरोध में ऐसा करने का एकमात्र तरीका हो सकता है। लेकिन यह वास्तव में वह दिशा नहीं है जो मैं जाना चाहता हूं।
टॉरन

क्लाइंट की आवश्यकताओं के कारण मैंने प्रतिक्रिया में सर्वर हेडर का उपयोग करके इस समस्या को हल किया ( Content-Disposition: attachment;filename="file.txt"), लेकिन मैं वास्तव में अगली बार इस दृष्टिकोण की कोशिश करना चाहता हूं। मैंने URIपहले थंबनेल के लिए डेटा का उपयोग किया था, लेकिन इसे डाउनलोड करने के लिए उपयोग करने के लिए मेरे साथ ऐसा कभी नहीं हुआ - इस डली को साझा करने के लिए धन्यवाद।
ब्रिचिंस

8

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

ग्राहक

var apples = new Array(); 
// construct data - replace with your own
$.ajax({
   type: "POST",
   url: '/Home/Download',
   data: JSON.stringify(apples),
   contentType: "application/json",
   dataType: "text",

   success: function (data) {
      var url = '/Home/Download?id=' + data;
      window.location = url;
   });
});

सर्वर

[HttpPost]
// called first
public ActionResult Download(Apple[] apples)
{
   string json = new JavaScriptSerializer().Serialize(apples);
   string id = Guid.NewGuid().ToString();
   string path = Server.MapPath(string.Format("~/temp/{0}.json", id));
   System.IO.File.WriteAllText(path, json);

   return Content(id);
}

// called next
public ActionResult Download(string id)
{
   string path = Server.MapPath(string.Format("~/temp/{0}.json", id));
   string json = System.IO.File.ReadAllText(path);
   System.IO.File.Delete(path);
   Apple[] apples = new JavaScriptSerializer().Deserialize<Apple[]>(json);

   // work with apples to build your file in memory
   byte[] file = createPdf(apples); 

   Response.AddHeader("Content-Disposition", "attachment; filename=juicy.pdf");
   return File(file, "application/pdf");
}

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

5
$scope.downloadSearchAsCSV = function(httpOptions) {
  var httpOptions = _.extend({
    method: 'POST',
    url:    '',
    data:   null
  }, httpOptions);
  $http(httpOptions).then(function(response) {
    if( response.status >= 400 ) {
      alert(response.status + " - Server Error \nUnable to download CSV from POST\n" + JSON.stringify(httpOptions.data));
    } else {
      $scope.downloadResponseAsCSVFile(response)
    }
  })
};
/**
 * @source: https://github.com/asafdav/ng-csv/blob/master/src/ng-csv/directives/ng-csv.js
 * @param response
 */
$scope.downloadResponseAsCSVFile = function(response) {
  var charset = "utf-8";
  var filename = "search_results.csv";
  var blob = new Blob([response.data], {
    type: "text/csv;charset="+ charset + ";"
  });

  if (window.navigator.msSaveOrOpenBlob) {
    navigator.msSaveBlob(blob, filename); // @untested
  } else {
    var downloadContainer = angular.element('<div data-tap-disabled="true"><a></a></div>');
    var downloadLink      = angular.element(downloadContainer.children()[0]);
    downloadLink.attr('href', window.URL.createObjectURL(blob));
    downloadLink.attr('download', "search_results.csv");
    downloadLink.attr('target', '_blank');

    $document.find('body').append(downloadContainer);

    $timeout(function() {
      downloadLink[0].click();
      downloadLink.remove();
    }, null);
  }

  //// Gets blocked by Chrome popup-blocker
  //var csv_window = window.open("","","");
  //csv_window.document.write('<meta name="content-type" content="text/csv">');
  //csv_window.document.write('<meta name="content-disposition" content="attachment;  filename=data.csv">  ');
  //csv_window.document.write(response.data);
};

3

मूल पोस्ट के लिए पूरी तरह से उत्तर नहीं है, लेकिन सर्वर पर एक जोंस-ऑब्जेक्ट पोस्ट करने और गतिशील रूप से डाउनलोड करने के लिए एक त्वरित और गंदा समाधान है।

ग्राहक पक्ष jQuery:

var download = function(resource, payload) {
     $("#downloadFormPoster").remove();
     $("<div id='downloadFormPoster' style='display: none;'><iframe name='downloadFormPosterIframe'></iframe></div>").appendTo('body');
     $("<form action='" + resource + "' target='downloadFormPosterIframe' method='post'>" +
      "<input type='hidden' name='jsonstring' value='" + JSON.stringify(payload) + "'/>" +
      "</form>")
      .appendTo("#downloadFormPoster")
      .submit();
}

.. और फिर सर्वर पर जौन-स्ट्रिंग को डिकोड करना और डाउनलोड के लिए हेडर सेट करना (PHP उदाहरण):

$request = json_decode($_POST['jsonstring']), true);
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename=export.csv');
header('Pragma: no-cache');

मुझे यह समाधान पसंद है। ओपी के प्रश्न में ऐसा लगता है कि अनुरोधकर्ता को पता है कि फ़ाइल डाउनलोड या JSON डेटा की अपेक्षा करनी है, इसलिए वह क्लाइंट एंड पर निर्णय ले सकता है और सर्वर एंड पर निर्णय लेने के बजाय एक अलग URL पर पोस्ट कर सकता है।
सैम

2

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

तो कॉल कैसे किया जाता है इसके आधार पर। (क्या इसका ब्राउज़र या वेब सेवा कॉल है) आप ब्राउज़र को URL भेजने और किसी अन्य वेब सेवा क्लाइंट को कच्चा डेटा भेजने के साथ, दो के संयोजन का उपयोग कर सकते हैं।


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

उपयोगकर्ता-एजेंट http हेडर द्वारा निर्धारित नहीं किया जा सकता है? या कोई और http हैडर?
naikus

1

मैं अब दो दिनों के लिए जाग रहा हूं, यह जानने की कोशिश कर रहा हूं कि अजाक्स कॉल के साथ jquery का उपयोग करके किसी फ़ाइल को कैसे डाउनलोड किया जाए। मुझे जो भी सहायता मिली, वह मेरी स्थिति में मदद नहीं कर सकी जब तक कि मैं यह कोशिश नहीं करता।

ग्राहक की ओर

function exportStaffCSV(t) {
   
    var postData = { checkOne: t };
    $.ajax({
        type: "POST",
        url: "/Admin/Staff/exportStaffAsCSV",
        data: postData,
        success: function (data) {
            SuccessMessage("file download will start in few second..");
            var url = '/Admin/Staff/DownloadCSV?data=' + data;
            window.location = url;
        },
       
        traditional: true,
        error: function (xhr, status, p3, p4) {
            var err = "Error " + " " + status + " " + p3 + " " + p4;
            if (xhr.responseText && xhr.responseText[0] == "{")
                err = JSON.parse(xhr.responseText).Message;
            ErrorMessage(err);
        }
    });

}

सर्वर साइड

 [HttpPost]
    public string exportStaffAsCSV(IEnumerable<string> checkOne)
    {
        StringWriter sw = new StringWriter();
        try
        {
            var data = _db.staffInfoes.Where(t => checkOne.Contains(t.staffID)).ToList();
            sw.WriteLine("\"First Name\",\"Last Name\",\"Other Name\",\"Phone Number\",\"Email Address\",\"Contact Address\",\"Date of Joining\"");
            foreach (var item in data)
            {
                sw.WriteLine(string.Format("\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\"",
                    item.firstName,
                    item.lastName,
                    item.otherName,
                    item.phone,
                    item.email,
                    item.contact_Address,
                    item.doj
                    ));
            }
        }
        catch (Exception e)
        {

        }
        return sw.ToString();

    }

    //On ajax success request, it will be redirected to this method as a Get verb request with the returned date(string)
    public FileContentResult DownloadCSV(string data)
    {
        return File(new System.Text.UTF8Encoding().GetBytes(data), System.Net.Mime.MediaTypeNames.Application.Octet, filename);
        //this method will now return the file for download or open.
    }

सौभाग्य।


2
यह काम करेगा, छोटी फाइलों के लिए। लेकिन अगर आपके पास एक बड़ी फाइल है, तो आप बहुत लंबे समय तक यूआरएल की समस्या में चलने वाले हैं। इसे 1,000 रिकॉर्ड के साथ आज़माएं, यह टूट जाएगा और केवल डेटा का हिस्सा निर्यात करेगा।
माइकल मेरेल

1

यह लंबे समय से पहले कहीं पाया और यह पूरी तरह से काम करता है!

let payload = {
  key: "val",
  key2: "val2"
};

let url = "path/to/api.php";
let form = $('<form>', {'method': 'POST', 'action': url}).hide();
$.each(payload, (k, v) => form.append($('<input>', {'type': 'hidden', 'name': k, 'value': v})) );
$('body').append(form);
form.submit();
form.remove();

0

सर्वर पर फ़ाइल को सहेजने और इसे पुनर्प्राप्त करने के बजाय, दूसरा एक्शन (जब यह निश्चित रूप से डंप किया जा सकता है) उस समय तक एक छोटी समाप्ति के साथ .NET 4.0+ ऑब्जेक्ट का उपयोग करना है। कॉल करने के लिए मुझे JQuery Ajax का उपयोग करने का कारण यह है कि यह अतुल्यकालिक है। मेरी डायनामिक पीडीएफ फाइल बनाने में काफी समय लगता है, और मैं उस दौरान एक व्यस्त स्पिनर संवाद प्रदर्शित करता हूं (यह अन्य काम भी करने देता है)। ब्लॉब बनाने के लिए "सफलता:" में दिए गए डेटा का उपयोग करने का दृष्टिकोण मज़बूती से काम नहीं करता है। यह पीडीएफ फाइल की सामग्री पर निर्भर करता है। यह प्रतिक्रिया में डेटा द्वारा आसानी से भ्रष्ट हो जाता है, अगर यह पूरी तरह से पाठ्य नहीं है जो कि अजाक्स को संभाल सकता है।


0

उपाय

सामग्री-विवाद लगाव मेरे लिए काम करता है:

self.set_header("Content-Type", "application/json")
self.set_header("Content-Disposition", 'attachment; filename=learned_data.json')

वैकल्पिक हल

आवेदन / ओकटेट धारा

मेरे पास JSON के साथ मेरे साथ कुछ ऐसा ही हो रहा था, मेरे लिए सर्वर साइड पर मैं हेडर को self.set_header ("सामग्री-प्रकार", " एप्लिकेशन / json ") पर सेट कर रहा था, हालांकि जब मैंने इसे बदला:

self.set_header("Content-Type", "application/octet-stream")

यह अपने आप डाउनलोड हो गया।

यह भी जान लें कि फ़ाइल को अभी भी .json प्रत्यय रखने के लिए आपको फ़ाइल नाम हेडर पर इसकी आवश्यकता होगी:

self.set_header("Content-Disposition", 'filename=learned_data.json')

-1

HTML5 के साथ, आप बस एक एंकर बना सकते हैं और उस पर क्लिक कर सकते हैं। इसे एक बच्चे के रूप में दस्तावेज़ में जोड़ने की आवश्यकता नहीं है।

const a = document.createElement('a');
a.download = '';
a.href = urlForPdfFile;
a.click();

सब कुछ कर दिया।

यदि आप डाउनलोड के लिए एक विशेष नाम रखना चाहते हैं, तो उसे downloadविशेषता में पास करें :

const a = document.createElement('a');
a.download = 'my-special-name.pdf';
a.href = urlForPdfFile;
a.click();

4
प्रश्न POST विधि के बारे में है
dovid
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.