ดาวน์โหลดไฟล์โดย jQuery.Ajax


420

ฉันมีการกระทำ Struts2 ในฝั่งเซิร์ฟเวอร์สำหรับการดาวน์โหลดไฟล์

<action name="download" class="com.xxx.DownAction">
    <result name="success" type="stream">
        <param name="contentType">text/plain</param>
        <param name="inputName">imageStream</param>
        <param name="contentDisposition">attachment;filename={fileName}</param>
        <param name="bufferSize">1024</param>
    </result>
</action>

อย่างไรก็ตามเมื่อฉันเรียกการกระทำโดยใช้ jQuery:

$.post(
  "/download.action",{
    para1:value1,
    para2:value2
    ....
  },function(data){
      console.info(data);
   }
);

ใน Firebug ผมเห็นข้อมูลจะถูกดึงมากับกระแสไบนารี ฉันสงสัยว่าจะเปิดหน้าต่างดาวน์โหลดไฟล์ซึ่งผู้ใช้สามารถบันทึกไฟล์ไว้ในเครื่องได้อย่างไร



1
ฉันทำเครื่องหมายว่าซ้ำซ้อนแม้ว่าจะมีความแตกต่างของแพลตฟอร์มเพราะเท่าที่ฉันเห็นโซลูชันนั้นเหมือนกัน (คุณไม่สามารถและไม่จำเป็นต้องทำสิ่งนี้ผ่าน Ajax)
Pekka

1
ดังนั้นโดยไม่ต้อง ajax เพียงใช้ window.location = "download.action? para1 = value1 .... "?
hguser

คำตอบ:


676

อัพเดตเบราว์เซอร์ที่ทันสมัยในปี 2019

นี่คือวิธีที่ฉันจะแนะนำในตอนนี้กับ caveats ไม่กี่:

  • ต้องการเบราว์เซอร์ที่ค่อนข้างทันสมัย
  • หากไฟล์ดังกล่าวมีขนาดใหญ่มากคุณควรทำสิ่งที่คล้ายกับวิธีดั้งเดิม (iframe และคุกกี้) เนื่องจากการดำเนินการด้านล่างบางอย่างอาจใช้หน่วยความจำระบบอย่างน้อยใหญ่เท่ากับไฟล์ที่ดาวน์โหลดและ / หรือ CPU ที่น่าสนใจอื่น ๆ ผลข้างเคียง.

fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(resp => resp.blob())
  .then(blob => {
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    // the filename you want
    a.download = 'todo-1.json';
    document.body.appendChild(a);
    a.click();
    window.URL.revokeObjectURL(url);
    alert('your file has downloaded!'); // or you know, something with better UX...
  })
  .catch(() => alert('oh no!'));

2012 jQuery / iframe / Cookie แบบดั้งเดิม

Bluishถูกต้องสมบูรณ์เกี่ยวกับเรื่องนี้คุณไม่สามารถทำได้ผ่าน Ajax เนื่องจาก JavaScript ไม่สามารถบันทึกไฟล์ลงในคอมพิวเตอร์ของผู้ใช้โดยตรง (เนื่องจากปัญหาด้านความปลอดภัย) โชคไม่ดีที่ชี้URL ของหน้าต่างหลักในการดาวน์โหลดไฟล์ของคุณหมายความว่าคุณสามารถควบคุมประสบการณ์การใช้งานของผู้ใช้ได้เมื่อการดาวน์โหลดไฟล์เกิดขึ้นเพียงเล็กน้อย

ฉันสร้างjQuery File Downloadที่ให้ประสบการณ์ "Ajax like" กับการดาวน์โหลดไฟล์ที่สมบูรณ์ด้วย OnSuccess และ OnFailure callback เพื่อมอบประสบการณ์การใช้งานที่ดียิ่งขึ้น ลองดูที่ฉันโพสต์บล็อกเกี่ยวกับปัญหาที่พบบ่อยว่าแก้ปลั๊กอินและวิธีการที่จะใช้มันและยังมีการสาธิตของ jQuery ดาวน์โหลดไฟล์ในการดำเนินการ นี่คือแหล่งที่มา

นี่คือตัวอย่างการใช้งานอย่างง่ายโดยใช้แหล่งปลั๊กอินพร้อมสัญญา หน้าสาธิตรวมถึงอื่น ๆ อีกมากมาย 'ดีกว่า UX' เป็นตัวอย่างที่ดี

$.fileDownload('some/file.pdf')
    .done(function () { alert('File download a success!'); })
    .fail(function () { alert('File download failed!'); });

ขึ้นอยู่กับเบราว์เซอร์ที่คุณต้องการสนับสนุนคุณอาจใช้https://github.com/eligrey/FileSaver.js/ซึ่งอนุญาตการควบคุมที่ชัดเจนกว่าการใช้วิธีการดาวน์โหลดไฟล์ jQuery ของ IFRAME


69
ฉันชอบสิ่งที่คุณสร้าง แต่ฉันสงสัยว่าจะได้รับเครดิต StackOverFlow มากขึ้นคำตอบของคุณที่นี่ควรมีรายละเอียดเพิ่มเติมเล็กน้อย โดยเฉพาะเกี่ยวกับวิธีที่คุณแก้ไขปัญหา
AnthonyVO

14
มันจะดีถ้าคุณจะพูดถึงวิธีการที่ "ปลั๊กอิน" นี้ได้รับข้อ จำกัด มากกว่าบังคับให้เราไปที่แหล่งบล็อก / ปลั๊กอินของคุณเพื่อดู ตัวอย่างเช่นจะเป็นการโพสต์ไปยัง iframe แทนหรือไม่ มันต้องการให้สคริปต์รีโมตแทนบันทึกไฟล์และส่งคืน url หรือไม่?
Kevin B

2
@asgerhallas แน่นอน แต่นั่นก็ไร้ประโยชน์อย่างสมบูรณ์ถ้าลิงก์ดังกล่าวหายไป
Kevin B

26
ฉันเห็นด้วยบล็อกเป็นสถานที่ที่ดีกว่ามากในการวางคำอธิบายที่มีความยาวของวิธีใช้ปลั๊กอินของคุณและวิธีการทำงาน แต่อย่างน้อยคุณอาจให้ภาพรวมสั้น ๆ ว่าปลั๊กอินนี้แก้ปัญหาอย่างไร ตัวอย่างเช่นวิธีนี้แก้ปัญหาโดยให้เซิร์ฟเวอร์ตั้งค่าคุกกี้และให้จาวาสคริปต์ของคุณค้นหาคุกกี้อย่างต่อเนื่องจนกว่าจะมีอยู่ เมื่อมีอยู่แล้วเราสามารถสรุปได้ว่าการดาวน์โหลดเสร็จสมบูรณ์ ด้วยข้อมูลประเภทนั้นเราสามารถม้วนโซลูชันของตนเองได้อย่างรวดเร็วและคำตอบนั้นไม่ต้องอาศัย 100% ในบล็อก / ปลั๊กอิน / jquery ของคุณอีกต่อไปและสามารถนำไปใช้กับห้องสมุดอื่น ๆ ได้
Kevin B

1
อย่างที่ฉันเข้าใจ AJAX ไม่สามารถรองรับการดาวน์โหลดไฟล์ที่ทำให้ป๊อปอัปดาวน์โหลดไฟล์บันทึกลงดิสก์ได้ คุณพบวิธีที่ฉันไม่รู้หรือไม่?
John Culviner

227

ไม่มีใครโพสต์วิธีแก้ปัญหาของ @ Pekka นี้ ... ดังนั้นฉันจะโพสต์ มันสามารถช่วยใครบางคน

คุณไม่จำเป็นต้องทำสิ่งนี้ผ่าน Ajax เพียงแค่ใช้

window.location="download.action?para1=value1...."

4
เป็นสิ่งที่ดี ... ขณะที่ฉันกำลังดิ้นรนกับการจัดการไฟล์แจ้งให้ดาวน์โหลดและใช้ jquery ajax .. และโซลูชันนี้ทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน .. + 1
swapnesh

45
โปรดทราบว่าสิ่งนี้ต้องการให้เซิร์ฟเวอร์ตั้งค่าเนื้อหาส่วนหัว - การจัดการของ 'สิ่งที่แนบ' มิฉะนั้นเบราว์เซอร์จะเปลี่ยนเส้นทางไปที่ (และแสดง) เนื้อหาการตอบสนอง
brichins

21
หรือมิฉะนั้นwindow.open(<url>, '_blank');ให้ใช้เพื่อให้แน่ใจว่าการดาวน์โหลดจะไม่แทนที่เนื้อหาเบราว์เซอร์ปัจจุบันของคุณ (ไม่ว่าจะเป็นส่วนหัวเนื้อหา
Christopher King

4
ปัญหาเกี่ยวกับการแก้ไขปัญหานี้คือหากการดำเนินการล้มเหลว / เซิร์ฟเวอร์ส่งคืนข้อผิดพลาดหน้าของคุณจะถูกเปลี่ยนเส้นทางไปยังหน้าข้อผิดพลาด เพื่อแก้ปัญหานั้นให้ใช้โซลูชัน iFrame
kofifus

4
ปัญหาที่แท้จริงของการแก้ปัญหานี้คือคำถามเกี่ยวกับการPOSTร้องขอ
Atomosk

35

คุณสามารถใช้ HTML5

หมายเหตุ: ข้อมูลไฟล์ที่ส่งคืนต้องเป็น base64 ที่เข้ารหัสเนื่องจากคุณไม่สามารถเข้ารหัส JSON ข้อมูลไบนารีได้

ในการAJAXตอบสนองของฉันฉันมีโครงสร้างข้อมูลที่มีลักษณะเช่นนี้:

{
    result: 'OK',
    download: {
        mimetype: string(mimetype in the form 'major/minor'),
        filename: string(the name of the file to download),
        data: base64(the binary data as base64 to download)
    }
}

นั่นหมายความว่าฉันสามารถทำสิ่งต่อไปนี้เพื่อบันทึกไฟล์ผ่าน AJAX

var a = document.createElement('a');
if (window.URL && window.Blob && ('download' in a) && window.atob) {
    // Do it the HTML5 compliant way
    var blob = base64ToBlob(result.download.data, result.download.mimetype);
    var url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = result.download.filename;
    a.click();
    window.URL.revokeObjectURL(url);
}

ฟังก์ชัน base64ToBlob ถูกนำมาจากที่นี่และจะต้องใช้ตามฟังก์ชันนี้

function base64ToBlob(base64, mimetype, slicesize) {
    if (!window.atob || !window.Uint8Array) {
        // The current browser doesn't have the atob function. Cannot continue
        return null;
    }
    mimetype = mimetype || '';
    slicesize = slicesize || 512;
    var bytechars = atob(base64);
    var bytearrays = [];
    for (var offset = 0; offset < bytechars.length; offset += slicesize) {
        var slice = bytechars.slice(offset, offset + slicesize);
        var bytenums = new Array(slice.length);
        for (var i = 0; i < slice.length; i++) {
            bytenums[i] = slice.charCodeAt(i);
        }
        var bytearray = new Uint8Array(bytenums);
        bytearrays[bytearrays.length] = bytearray;
    }
    return new Blob(bytearrays, {type: mimetype});
};

นี่เป็นสิ่งที่ดีถ้าเซิร์ฟเวอร์ของคุณกำลังบันทึกไฟล์ataที่จะบันทึก อย่างไรก็ตามฉันยังไม่ค่อยทราบวิธีที่จะใช้ HTML4 fallback


1
a.click()ดูเหมือนจะไม่ทำงานใน Firefox ... ความคิดใด?
bigpony

ในเบราว์เซอร์บางตัวคุณอาจต้องเพิ่มลงaไปใน dom เพื่อให้โค้ดนี้ทำงานและ / หรือลบrevokeObjectURLส่วนออก:document.body.appendChild(a)
bigpony

บันทึกวันของฉัน (และอาจจะเป็นงานด้วย :)) ไม่ใช่ผู้เชี่ยวชาญจาวาสคริปต์โดยใช้วิธีการใด ๆ ... เพิ่มเติมจาวาคนที่แต่งตัวประหลาด อย่างไรก็ตามฉันไม่รู้ว่าทำไม "createObjectURL (Blob ใหม่ ([atob (base64)]])) แบบธรรมดา" ใช้งานไม่ได้! มันก็ไม่ได้ในขณะที่สัญชาตญาณทั้งหมดบอกว่ามันต้อง
grrr

ที่เส้นมันจะพ่นข้อผิดพลาดvar bytechars = atob(base64) JavaScript runtime error: InvalidCharacterErrorฉันใช้ Chrome เวอร์ชัน 75.0.3770.142 แต่ฉันไม่รู้ว่าเกิดอะไรขึ้นที่นี่
Muflix

27

1. Framework agnostic: Servlet ดาวน์โหลดไฟล์เป็นไฟล์แนบ

<!-- with JS -->
<a href="javascript:window.location='downloadServlet?param1=value1'">
    download
</a>

<!-- without JS -->
<a href="downloadServlet?param1=value1" >download</a>

2. Struts2 Framework: การดำเนินการดาวน์โหลดไฟล์เป็นไฟล์แนบ

<!-- with JS -->
<a href="javascript:window.location='downloadAction.action?param1=value1'">
    download
</a>

<!-- without JS -->
<a href="downloadAction.action?param1=value1" >download</a>

มันจะเป็นการดีกว่าถ้าใช้<s:a>แท็กที่มีOGNLกับURL ที่สร้างด้วย<s:url>แท็ก:

<!-- without JS, with Struts tags: THE RIGHT WAY -->    
<s:url action="downloadAction.action" var="url">
    <s:param name="param1">value1</s:param>
</s:ulr>
<s:a href="%{url}" >download</s:a>

ในกรณีข้างต้นคุณต้องเขียนส่วนหัวของเนื้อหา - การจัดการการตอบสนองโดยระบุว่าไฟล์จะต้องมีการดาวน์โหลด ( attachment) และไม่ได้เปิดโดยเบราว์เซอร์ ( inline) คุณต้องระบุประเภทเนื้อหาด้วยและคุณอาจต้องการเพิ่มชื่อไฟล์และความยาว (เพื่อช่วยให้เบราว์เซอร์วาดแถบความคืบหน้าตามจริง)

ตัวอย่างเช่นเมื่อดาวน์โหลด ZIP:

response.setContentType("application/zip");
response.addHeader("Content-Disposition", 
                   "attachment; filename=\"name of my file.zip\"");
response.setHeader("Content-Length", myFile.length()); // or myByte[].length...

ด้วย Struts2 (ยกเว้นว่าคุณกำลังใช้ Action เป็น Servlet, แฮ็คสำหรับการสตรีมโดยตรง ) คุณไม่จำเป็นต้องเขียนอะไรลงไปในคำตอบโดยตรง เพียงใช้ประเภทผลการสตรีมและกำหนดค่าใน struts.xml จะทำงาน: ตัวอย่าง

<result name="success" type="stream">
   <param name="contentType">application/zip</param>
   <param name="contentDisposition">attachment;filename="${fileName}"</param>
   <param name="contentLength">${fileLength}</param>
</result>

3. Framework agnostic (/ Struts2 framework): การเปิดไฟล์ Servlet (/ Action) ภายในเบราว์เซอร์

หากคุณต้องการเปิดไฟล์ภายในเบราว์เซอร์แทนที่จะดาวน์โหลดไฟล์ต้องกำหนดเนื้อหาการจัดการเป็นแบบอินไลน์แต่เป้าหมายไม่สามารถเป็นตำแหน่งหน้าต่างปัจจุบันได้ คุณต้องกำหนดเป้าหมายหน้าต่างใหม่ที่สร้างขึ้นโดย javascript, <iframe>ในหน้า, หรือหน้าต่างใหม่ที่สร้างขึ้นทันที, ด้วย "ที่กล่าวถึง" target = "_ blank":

<!-- From a parent page into an IFrame without javascript -->   
<a href="downloadServlet?param1=value1" target="iFrameName">
    download
</a>

<!-- In a new window without javascript --> 
<a href="downloadServlet?param1=value1" target="_blank">
    download
</a>

<!-- In a new window with javascript -->    
<a href="javascript:window.open('downloadServlet?param1=value1');" >
    download
</a>

2
เซอร์อินพุตของคุณ: "Content-Disposition", "inline; .... บันทึกวันรหัสผู้น่าสงสาร :)
Vedran Maricevic

1
นี่เป็นคำตอบเดียวที่กล่าวถึง "window.open" (หนึ่งในความคิดเห็นที่กล่าวถึง)
Andrew Koster

มันไม่ทำงานหากคุณมีพารามิเตอร์จำนวนมากเพราะคุณจะได้รับtoo long urlข้อผิดพลาด
Muflix

25

วิธีง่ายๆในการทำให้เบราว์เซอร์ดาวน์โหลดไฟล์คือทำการร้องขอเช่นนั้น:

 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();
 }

นี่เป็นการเปิดการดาวน์โหลดเบราว์เซอร์ขึ้นมา


3
ขอบคุณฉันใช้วิธีนี้ ทำงานเหมือนจับใจ นอกจากนี้หากคุณไม่ได้รับหยดจากการตอบสนองเพียงแค่สร้าง Blob ใหม่
fabio.sang

6
รุ่นที่ดีกว่าพร้อมลิงค์การ
เริ่มด้วย 7_18

ลิงค์จาก @startsWith_R ช่วยได้จริงถ้าคุณทำงานกับ IE11
alexventuraio

ขอบคุณมันใช้งานได้สำหรับฉัน!
Zaki Mohammed

23

ฉันได้สร้างฟังก์ชั่นเล็ก ๆ น้อย ๆ เป็นวิธีแก้ปัญหา (แรงบันดาลใจจากปลั๊กอิน @JohnCulviner):

// creates iframe and form in it with hidden field,
// then submit form with provided data
// url - form url
// data - data to form field
// input_name - form hidden input name

function ajax_download(url, data, input_name) {
    var $iframe,
        iframe_doc,
        iframe_html;

    if (($iframe = $('#download_iframe')).length === 0) {
        $iframe = $("<iframe id='download_iframe'" +
                    " style='display: none' src='about:blank'></iframe>"
                   ).appendTo("body");
    }

    iframe_doc = $iframe[0].contentWindow || $iframe[0].contentDocument;
    if (iframe_doc.document) {
        iframe_doc = iframe_doc.document;
    }

    iframe_html = "<html><head></head><body><form method='POST' action='" +
                  url +"'>" +
                  "<input type=hidden name='" + input_name + "' value='" +
                  JSON.stringify(data) +"'/></form>" +
                  "</body></html>";

    iframe_doc.open();
    iframe_doc.write(iframe_html);
    $(iframe_doc).find('form').submit();
}

ตัวอย่างเหตุการณ์การคลิก:

$('#someid').on('click', function() {
    ajax_download('/download.action', {'para1': 1, 'para2': 2}, 'dataname');
});

ที่ส่งข้อมูลในทางแปลกมากไปยังเซิร์ฟเวอร์ว่า ฉันสงสัยว่าอาจมีการเปลี่ยนแปลงเพื่อสร้าง POST ที่สอดคล้องหรือไม่
Shayne

16

ฉันประสบปัญหาเดียวกันและแก้ไขได้สำเร็จ กรณีการใช้งานของฉันคือสิ่งนี้

" โพสต์ข้อมูล JSON ไปยังเซิร์ฟเวอร์และรับไฟล์ excel ไฟล์ excel นั้นสร้างโดยเซิร์ฟเวอร์และส่งคืนเป็นการตอบกลับไปยังไคลเอนต์ดาวน์โหลดการตอบสนองนั้นเป็นไฟล์ที่มีชื่อที่กำหนดเองในเบราว์เซอร์ "

$("#my-button").on("click", function(){

// Data to post
data = {
    ids: [1, 2, 3, 4, 5]
};

// Use XMLHttpRequest instead of Jquery $ajax
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    var a;
    if (xhttp.readyState === 4 && xhttp.status === 200) {
        // Trick for making downloadable link
        a = document.createElement('a');
        a.href = window.URL.createObjectURL(xhttp.response);
        // Give filename you wish to download
        a.download = "test-file.xls";
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
    }
};
// Post data to URL which handles post request
xhttp.open("POST", excelDownloadUrl);
xhttp.setRequestHeader("Content-Type", "application/json");
// You should set responseType as blob for binary responses
xhttp.responseType = 'blob';
xhttp.send(JSON.stringify(data));
});

ตัวอย่างด้านบนกำลังทำตาม

  • การโพสต์อาร์เรย์เป็น JSON ไปยังเซิร์ฟเวอร์โดยใช้ XMLHttpRequest
  • หลังจากดึงเนื้อหาเป็นหยด (ไบนารี่) เรากำลังสร้าง URL ที่สามารถดาวน์โหลดได้และแนบไปยังลิงค์ "a" ที่มองไม่เห็นจากนั้นคลิก ฉันทำคำขอ POST ที่นี่ คุณสามารถรับ GET ง่ายๆได้เช่นกัน เราไม่สามารถดาวน์โหลดไฟล์ผ่าน Ajax ต้องใช้ XMLHttpRequest

ที่นี่เราจำเป็นต้องตั้งค่าบางอย่างในฝั่งเซิร์ฟเวอร์อย่างระมัดระวัง ฉันตั้งค่าส่วนหัวเล็กน้อยใน Python Django HttpResponse คุณต้องตั้งค่าให้เหมาะสมหากคุณใช้ภาษาโปรแกรมอื่น

# In python django code
response = HttpResponse(file_content, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")

เนื่องจากฉันดาวน์โหลด xls (excel) ที่นี่ฉันจึงปรับ contentType ให้อยู่เหนือระดับ คุณต้องตั้งค่าตามประเภทไฟล์ของคุณ คุณสามารถใช้เทคนิคนี้เพื่อดาวน์โหลดไฟล์ประเภทใดก็ได้


"เราไม่สามารถดาวน์โหลดไฟล์ผ่าน Ajax ต้องใช้ XMLHttpRequest" XMLHttpRequest เป็น AJAX ตามคำจำกัดความ เป็นทางออกที่ดีสำหรับเว็บเบราว์เซอร์ที่ทันสมัย สำหรับ IE ซึ่งไม่รองรับHTMLAnchorElement.downloadฉันคิดว่าจะรวมมันเข้ากับวิธีmsSaveOrOpenBlob ที่เป็นกรรมสิทธิ์
Tsahi Asher

15

Ok ตามโค้ดของ ndpu นี่คือรุ่น ajax_download (ฉันคิดว่า) -

function ajax_download(url, data) {
    var $iframe,
        iframe_doc,
        iframe_html;

    if (($iframe = $('#download_iframe')).length === 0) {
        $iframe = $("<iframe id='download_iframe'" +
                    " style='display: none' src='about:blank'></iframe>"
                   ).appendTo("body");
    }

    iframe_doc = $iframe[0].contentWindow || $iframe[0].contentDocument;
    if (iframe_doc.document) {
        iframe_doc = iframe_doc.document;
    }

    iframe_html = "<html><head></head><body><form method='POST' action='" +
                  url +"'>" 

    Object.keys(data).forEach(function(key){
        iframe_html += "<input type='hidden' name='"+key+"' value='"+data[key]+"'>";

    });

        iframe_html +="</form></body></html>";

    iframe_doc.open();
    iframe_doc.write(iframe_html);
    $(iframe_doc).find('form').submit();
}

ใช้สิ่งนี้เช่นนี้ -

$('#someid').on('click', function() {
    ajax_download('/download.action', {'para1': 1, 'para2': 2});
});

พารามิเตอร์จะถูกส่งเป็นพารามิเตอร์โพสต์ที่เหมาะสมราวกับว่ามาจากอินพุตแทนที่จะเป็นสตริงที่เข้ารหัส json ตามตัวอย่างก่อนหน้านี้

ถ้ำ: ระวังเกี่ยวกับศักยภาพในการฉีดตัวแปรในรูปแบบเหล่านั้น อาจมีวิธีที่ปลอดภัยกว่าในการเข้ารหัสตัวแปรเหล่านั้น พิจารณาอีกทางเลือกหนึ่งหนีพวกเขา


นี่คือตัวอย่างการทำงาน ขอบคุณ เป็นไปได้ที่จะทำเช่นนั้นโดยไม่มี iframe แต่ไม่มี window.location?
Marek Bar

ฉันคิดว่าคุณสามารถต่อท้ายแบบฟอร์มที่ซ่อนอยู่ที่ด้านล่างของ DOM การสำรวจที่คุ้มค่าก็คือการใช้ Shadow dom แม้ว่าจะไม่รองรับเบราว์เซอร์รุ่นเก่า
เชน

ในรหัสนี้ฉันได้รับข้อผิดพลาดนี้ Uncaught SecurityError: Blocked a frame with origin "http://foo.bar.com" from accessing a frame with origin "null". The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "data". Protocols must match.
ถือเป็นโมฆะ

ฉันจะแมปแบบฟอร์มนี้กับคลาสโมเดลได้อย่างไร ฉันมี: @ResourceMapping() public void downloadFile(final ResourceRequest request, final ResourceResponse response, @ModelAttribute("downForm") FormModel model) แต่มันใช้งานไม่ได้ ..
bartex9

เป็นโมฆะ: นั่นน่าจะเป็นปัญหาความปลอดภัยข้ามแหล่งที่มา นั่นอาจเป็นคำถามที่ล้นทั้งในและด้วยตนเอง @ bartex9: นั่นจะขึ้นอยู่กับว่าคุณใช้เฟรมเวิร์กประเภทใด แต่หลักการก็คือการใช้ชื่อและพา ธ และเก็บไว้ในขณะที่ผลักไฟล์เข้าสู่พื้นที่เว็บที่สามารถเข้าถึงได้ของระบบไฟล์หรือสิ่งที่คล้ายกับ amazon S3 เพื่อความพร้อมใช้งานสูง
Shayne

8

นี่คือสิ่งที่ฉันทำคือจาวาสคริปต์ที่บริสุทธิ์และ html ไม่ได้ทดสอบ แต่สิ่งนี้ควรใช้ได้กับเบราว์เซอร์ทั้งหมด

ฟังก์ชั่น Javascript

var iframe = document.createElement('iframe');
iframe.id = "IFRAMEID";
iframe.style.display = 'none';
document.body.appendChild(iframe);
iframe.src = 'SERVERURL'+'?' + $.param($scope.filtro);
iframe.addEventListener("load", function () {
     console.log("FILE LOAD DONE.. Download should start now");
});

การใช้เพียงส่วนประกอบที่ได้รับการสนับสนุนในเบราว์เซอร์ทั้งหมดไม่มีไลบรารีเพิ่มเติม

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

นี่คือโค้ดควบคุม JAVA Spring ของฝั่งเซิร์ฟเวอร์ของฉัน

@RequestMapping(value = "/rootto/my/xlsx", method = RequestMethod.GET)
public void downloadExcelFile(@RequestParam(value = "param1", required = false) String param1,
    HttpServletRequest request, HttpServletResponse response)
            throws ParseException {

    Workbook wb = service.getWorkbook(param1);
    if (wb != null) {
        try {
            String fileName = "myfile_" + sdf.format(new Date());
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-disposition", "attachment; filename=\"" + fileName + ".xlsx\"");
            wb.write(response.getOutputStream());
            response.getOutputStream().close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    }

ดูเหมือนว่าเหตุการณ์การโหลดของคุณจะไม่ถูกเรียกสำหรับเนื้อหาสิ่งที่แนบมากับเนื้อหาการจัดการ (เพราะไม่มีอะไรโหลดลงใน iframe) ถ้ามันเหมาะกับคุณ (คุณจะได้รับ console.log) กรุณาโพสต์ตัวอย่าง
kofifus

นี่คือซออย่างรวดเร็วjsfiddle.net/y2xezyojนี่จะทำให้เกิดเหตุการณ์โหลดขึ้นในไม่ช้าเมื่อไฟล์ PDF ถูกโหลดเข้าสู่ iframe .. ซอนี้ไม่ได้ดาวน์โหลดเพราะกุญแจสำหรับการดาวน์โหลดนั้นอยู่ในฝั่งเซิร์ฟเวอร์ "response.setHeader (" เนื้อหา -disposition "," ไฟล์แนบ ; filename = \ "" + fileName + ".xlsx \" ");"
manukyanv07

1
ใช่มันจะทำงานในกรณีนั้น แต่ถ้าไฟล์ถูกดาวน์โหลดนั่นคือเซิร์ฟเวอร์จะส่งเนื้อหา - การจัดการ: สิ่งที่แนบมาดังนั้นเหตุการณ์การโหลดจะไม่เริ่มทำงานซึ่งเป็นจุดของฉัน
kofifus

คุณโหลดเหตุการณ์ทั้งหมดถูกต้องหลังจากเซิร์ฟเวอร์เสร็จสิ้นการประมวลผลเริ่มส่งไฟล์ นี่คือสิ่งที่ฉันกำลังมองหา 1- บล็อกปุ่มและแสดงการประมวลผลเพื่อให้ผู้ใช้สามารถมีข้อเสนอแนะว่าสิ่งที่เกิดขึ้น 2 - จากนั้นเมื่อเซิร์ฟเวอร์ประมวลผลเสร็จแล้วและกำลังจะส่งไฟล์ 3 (เหตุการณ์โหลดถูกไล่ออก) ที่ฉันปลดล็อคปุ่มและลบการประมวลผลสปินเนอร์ 4 - ผู้ใช้จะปรากฏขึ้นพร้อมไฟล์บันทึกหรือเบราว์เซอร์เริ่มดาวน์โหลดใน ตำแหน่งดาวน์โหลดที่กำหนด ขอโทษด้วยภาษาอังกฤษของฉัน
manukyanv07

5
function downloadURI(uri, name) 
{
    var link = document.createElement("a");
    link.download = name;
    link.href = uri;
    link.click();
}

คุณอธิบายคำตอบของคุณได้ไหม นั่นจะช่วยให้ผู้อื่นเข้าใจสิ่งที่คุณทำเพื่อให้พวกเขาสามารถใช้เทคนิคของคุณกับสถานการณ์ของพวกเขา
Wai Ha Lee

2
เพียงคำเตือน: Safari และ IE ไม่รองรับdownloadคุณสมบัติดังนั้นไฟล์ของคุณจะจบลงด้วยชื่อ "ไม่ทราบ"
Yangshun Tay

4

ใน Rails ฉันทำอย่างนี้

function download_file(file_id) {
  let url       = '/files/' + file_id + '/download_file';
    $.ajax({
    type: 'GET',
    url: url,
    processData: false,
    success: function (data) {
       window.location = url;
    },
    error: function (xhr) {
     console.log(' Error:  >>>> ' + JSON.stringify(xhr));
    }
   });
 }

เคล็ดลับคือส่วนwindow.location วิธีการควบคุมดูเหมือนว่า:

# GET /files/{:id}/download_file/
def download_file
    send_file(@file.file,
          :disposition => 'attachment',
          :url_based_filename => false)
end

2
คำถามด่วนสิ่งนี้จะไม่สร้างไฟล์สองครั้งหรือไม่ เมื่อคุณส่งคำขออาแจ็กซ์ จากนั้นคุณทำให้หน้าเปลี่ยนเส้นทางไปยัง URL เดียวกันเช่นกัน เราจะกำจัดมันได้อย่างไร
coderhs

ไม่ใช่ในกรณีของฉัน ฉันทดสอบบน Chrome เท่านั้น
aarkerio

เมื่อ coderhs ระบุไว้อย่างถูกต้องแล้วการดำเนินการจะถูกเรียกสองครั้ง
Sven

มันก็ถูกเรียกมาสองครั้งสำหรับฉันเช่นกัน
CSquared

4

ใช้window.open https://developer.mozilla.org/en-US/docs/Web/API/Window/open

ตัวอย่างเช่นคุณสามารถวางรหัสบรรทัดนี้ลงในตัวจัดการการคลิก:

window.open('/file.txt', '_blank');

มันจะเปิดแท็บใหม่ (เนื่องจากชื่อหน้าต่าง '_blank') และแท็บนั้นจะเปิด URL

รหัสฝั่งเซิร์ฟเวอร์ของคุณควรมีลักษณะดังนี้:

res.set('Content-Disposition', 'attachment; filename=file.txt');

และด้วยวิธีนี้เบราว์เซอร์ควรแจ้งให้ผู้ใช้บันทึกไฟล์ลงดิสก์แทนที่จะแสดงไฟล์ มันจะปิดแท็บที่เพิ่งเปิดโดยอัตโนมัติ


4

ฉันพยายามดาวน์โหลดไฟล์ CSV แล้วทำบางสิ่งหลังจากการดาวน์โหลดเสร็จสิ้น ดังนั้นฉันต้องใช้callbackฟังก์ชั่นที่เหมาะสม

การใช้window.location="..."ไม่ใช่ความคิดที่ดีเพราะฉันไม่สามารถใช้งานโปรแกรมหลังจากเสร็จสิ้นการดาวน์โหลด อย่างนี้เปลี่ยนหัวข้อดังนั้นมันไม่ใช่ความคิดที่ดี

fetchเป็นทางเลือกที่ดี แต่ไม่สามารถรองรับ IE 11ได้ และwindow.URL.createObjectURLไม่สามารถรองรับ IE 11.You สามารถดูนี้

นี่คือรหัสของฉันมันคล้ายกับรหัสของ Shahrukh Alam แต่คุณควรระวังว่าwindow.URL.createObjectURLอาจสร้างความจำรั่ว คุณสามารถดูนี้ เมื่อการตอบสนองมาถึงข้อมูลจะถูกเก็บไว้ในหน่วยความจำของเบราว์เซอร์ ดังนั้นก่อนที่คุณจะคลิกaลิงค์ไฟล์จะถูกดาวน์โหลด หมายความว่าคุณสามารถทำอะไรได้หลังจากดาวน์โหลด

$.ajax({
    url: 'your download url',
    type: 'GET',
}).done(function (data, textStatus, request) {
    // csv => Blob
    var blob = new Blob([data]);

    // the file name from server.
    var fileName = request.getResponseHeader('fileName');

    if (window.navigator && window.navigator.msSaveOrOpenBlob) { // for IE
    window.navigator.msSaveOrOpenBlob(blob, fileName);
    } else { // for others
    var url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    a.download = fileName;
    document.body.appendChild(a);
    a.click();
    window.URL.revokeObjectURL(url);

    //Do something after download 
    ...

    }
}).then(after_download)
}

4

วิธีดาวน์โหลดไฟล์หลังจากได้รับจาก AJAX

สะดวกเมื่อสร้างไฟล์เป็นเวลานานและคุณต้องแสดง PRELOADER

ตัวอย่างเมื่อส่งแบบฟอร์มเว็บ:

<script>
$(function () {
    $('form').submit(function () {
        $('#loader').show();
        $.ajax({
            url: $(this).attr('action'),
            data: $(this).serialize(),
            dataType: 'binary',
            xhrFields: {
                'responseType': 'blob'
            },
            success: function(data, status, xhr) {
                $('#loader').hide();
                // if(data.type.indexOf('text/html') != -1){//If instead of a file you get an error page
                //     var reader = new FileReader();
                //     reader.readAsText(data);
                //     reader.onload = function() {alert(reader.result);};
                //     return;
                // }
                var link = document.createElement('a'),
                    filename = 'file.xlsx';
                // if(xhr.getResponseHeader('Content-Disposition')){//filename 
                //     filename = xhr.getResponseHeader('Content-Disposition');
                //     filename=filename.match(/filename="(.*?)"/)[1];
                //     filename=decodeURIComponent(escape(filename));
                // }
                link.href = URL.createObjectURL(data);
                link.download = filename;
                link.click();
            }
        });
        return false;
    });
});
</script>

ฟังก์ชั่นเสริมมีการใส่ความคิดเห็นเพื่อทำให้ตัวอย่างง่ายขึ้น

ไม่จำเป็นต้องสร้างไฟล์ชั่วคราวบนเซิร์ฟเวอร์

ใน jQuery v2.2.4 ตกลง จะมีข้อผิดพลาดในเวอร์ชั่นเก่า:

Uncaught DOMException: Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is '' or 'text' (was 'blob').

จะได้รับชื่อไฟล์จาก Disposition เนื้อหา, การแข่งขันครั้งนี้ทำงานให้ฉัน: filename.match(/filename=(.*)/)[1](โดยไม่มีคำพูดคู่หรือเครื่องหมายคำถาม) - regex101.com/r/2AsD4y/2 อย่างไรก็ตามโซลูชันของคุณเป็นโซลูชันเดียวที่ทำงานหลังจากค้นหามาก
jstuardo

3

การเพิ่มบางสิ่งเพิ่มเติมเพื่อตอบข้างบนสำหรับการดาวน์โหลดไฟล์

ด้านล่างเป็นโค้ด Java Spring ที่สร้างไบต์อาร์เรย์

@RequestMapping(value = "/downloadReport", method = { RequestMethod.POST })
    public ResponseEntity<byte[]> downloadReport(
            @RequestBody final SomeObejct obj, HttpServletResponse response) throws Exception {

        OutputStream out = new ByteArrayOutputStream();
        // write something to output stream
        HttpHeaders respHeaders = new HttpHeaders();
        respHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        respHeaders.add("X-File-Name", name);
        ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
        return new ResponseEntity<byte[]>(bos.toByteArray(), respHeaders, HttpStatus.CREATED);
    }

ขณะนี้อยู่ในรหัสจาวาสคริปต์โดยใช้ FileSaver.js สามารถดาวน์โหลดไฟล์ด้วยรหัสด้านล่าง

var json=angular.toJson("somejsobject");
var url=apiEndPoint+'some url';
var xhr = new XMLHttpRequest();
//headers('X-File-Name')
xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 201) {
        var res = this.response;
        var fileName=this.getResponseHeader('X-File-Name');
        var data = new Blob([res]);
        saveAs(data, fileName); //this from FileSaver.js
    }
}    
xhr.open('POST', url);
xhr.setRequestHeader('Authorization','Bearer ' + token);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.responseType = 'arraybuffer';
xhr.send(json);

ด้านบนจะทำการดาวน์โหลดไฟล์


2

ตกลงดังนั้นนี่คือรหัสการทำงานเมื่อใช้ MVC และคุณได้รับไฟล์จากคอนโทรลเลอร์

สมมติว่าคุณมีอาร์เรย์ไบต์ของคุณประกาศและเติมสิ่งเดียวที่คุณต้องทำคือการใช้ฟังก์ชั่นไฟล์ (ใช้ System.Web.Mvc)

byte[] bytes = .... insert your bytes in the array
return File(bytes, System.Net.Mime.MediaTypeNames.Application.Octet, "nameoffile.exe");

จากนั้นในคอนโทรลเลอร์เดียวกันเพิ่มฟังก์ชั่นที่ 2

protected override void OnResultExecuting(ResultExecutingContext context)
    {
        CheckAndHandleFileResult(context);

        base.OnResultExecuting(context);
    }

    private const string FILE_DOWNLOAD_COOKIE_NAME = "fileDownload";

    /// <summary>
    /// If the current response is a FileResult (an MVC base class for files) then write a
    /// cookie to inform jquery.fileDownload that a successful file download has occured
    /// </summary>
    /// <param name="context"></param>
    private void CheckAndHandleFileResult(ResultExecutingContext context)
    {
        if (context.Result is FileResult)
            //jquery.fileDownload uses this cookie to determine that a file download has completed successfully
            Response.SetCookie(new HttpCookie(FILE_DOWNLOAD_COOKIE_NAME, "true") { Path = "/" });
        else
            //ensure that the cookie is removed in case someone did a file download without using jquery.fileDownload
            if (Request.Cookies[FILE_DOWNLOAD_COOKIE_NAME] != null)
                Response.Cookies[FILE_DOWNLOAD_COOKIE_NAME].Expires = DateTime.Now.AddYears(-1);
    }

จากนั้นคุณจะสามารถเรียกคอนโทรลเลอร์ของคุณเพื่อดาวน์โหลดและรับการติดต่อกลับ "สำเร็จ" หรือ "ล้มเหลว"

$.fileDownload(mvcUrl('name of the controller'), {
            httpMethod: 'POST',
            successCallback: function (url) {
            //insert success code

            },
            failCallback: function (html, url) {
            //insert fail code
            }
        });

1

ฉันพบวิธีแก้ไขที่แม้ว่าจะไม่ได้ใช้ ajax จริงๆมันช่วยให้คุณใช้การเรียกใช้จาวาสคริปต์เพื่อร้องขอการดาวน์โหลดแล้วรับการติดต่อกลับเมื่อการดาวน์โหลดเริ่มขึ้นจริง ฉันพบสิ่งนี้มีประโยชน์หากลิงก์รันสคริปต์ฝั่งเซิร์ฟเวอร์ซึ่งใช้เวลาเล็กน้อยในการเขียนไฟล์ก่อนที่จะส่ง เพื่อให้คุณสามารถแจ้งเตือนพวกเขาว่ามันกำลังดำเนินการอยู่และจากนั้นเมื่อมันส่งไฟล์ให้ลบการแจ้งเตือนการประมวลผลในที่สุด นี่คือสาเหตุที่ฉันต้องการลองโหลดไฟล์ด้วย ajax เพื่อเริ่มต้นเพื่อที่ฉันจะได้มีเหตุการณ์เกิดขึ้นเมื่อมีการร้องขอไฟล์และอีกอันเมื่อเริ่มทำการดาวน์โหลด

js ในหน้าแรก

function expdone()
{
    document.getElementById('exportdiv').style.display='none';
}
function expgo()
{
   document.getElementById('exportdiv').style.display='block';
   document.getElementById('exportif').src='test2.php?arguments=data';
}

iframe

<div id="exportdiv" style="display:none;">
<img src="loader.gif"><br><h1>Generating Report</h1>
<iframe id="exportif" src="" style="width: 1px;height: 1px; border:0px;"></iframe>
</div>

ดังนั้นไฟล์อื่น ๆ :

<!DOCTYPE html>
<html>
<head>
<script>
function expdone()
{
    window.parent.expdone();
}
</script>
</head>
<body>
<iframe id="exportif" src="<?php echo "http://10.192.37.211/npdtracker/exportthismonth.php?arguments=".$_GET["arguments"]; ?>"></iframe>
<script>document.getElementById('exportif').onload= expdone;</script>
</body></html>

ฉันคิดว่ามีวิธีอ่านรับข้อมูลโดยใช้ js ดังนั้นไม่จำเป็นต้องใช้ php แต่ฉันไม่รู้ว่ามันใช้งานไม่ได้และเซิร์ฟเวอร์ที่ฉันใช้รองรับ php ดังนั้นสิ่งนี้จึงเหมาะกับฉัน คิดว่าฉันจะแบ่งปันมันในกรณีที่ช่วยใครก็ได้


0

หากคุณต้องการใช้การดาวน์โหลดไฟล์ jQuery โปรดทราบสิ่งนี้สำหรับ IE คุณต้องรีเซ็ตการตอบกลับไม่เช่นนั้นจะไม่ดาวน์โหลด

    //The IE will only work if you reset response
    getServletResponse().reset();
    //The jquery.fileDownload needs a cookie be set
    getServletResponse().setHeader("Set-Cookie", "fileDownload=true; path=/");
    //Do the reset of your action create InputStream and return

การกระทำของคุณสามารถนำServletResponseAware ไปใช้ในการเข้าถึงgetServletResponse()


0

มีบางอย่างที่คุณไม่สามารถทำได้ผ่านการโทร Ajax

อย่างไรก็ตามมีวิธีแก้ปัญหาคือ

ขั้นตอน:

หากคุณใช้ form.submit () เพื่อดาวน์โหลดไฟล์สิ่งที่คุณสามารถทำได้คือ:

  1. สร้างการโทร ajax จากไคลเอนต์ไปยังเซิร์ฟเวอร์และจัดเก็บสตรีมไฟล์ภายในเซสชัน
  2. เมื่อส่งคืน "สำเร็จ" จากเซิร์ฟเวอร์ให้โทร form.submit () ของคุณเพื่อสตรีมไฟล์สตรีมที่จัดเก็บในเซสชัน

สิ่งนี้มีประโยชน์ในกรณีที่คุณต้องการตัดสินใจว่าจะต้องดาวน์โหลดไฟล์หรือไม่หลังจากทำการ form.submit () เช่นอาจมีกรณีที่ form.submit () เกิดข้อยกเว้นที่ฝั่งเซิร์ฟเวอร์แทน จากความล้มเหลวคุณอาจต้องแสดงข้อความที่กำหนดเองในฝั่งไคลเอ็นต์ในกรณีเช่นนี้การใช้งานอาจช่วยได้


0

มีวิธีการอื่นในการดาวน์โหลดเว็บเพจใน ajax แต่ฉันหมายถึงหน้าที่ต้องดำเนินการก่อนแล้วจึงดาวน์โหลด

ก่อนอื่นคุณต้องแยกการประมวลผลหน้าออกจากการดาวน์โหลดผลลัพธ์

1) เฉพาะการคำนวณหน้าเท่านั้นในการโทร ajax

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

       ฟังก์ชั่น (ข้อมูลสถานะ) 
       {
            ถ้า (status == "สำเร็จ") 
            {
                / * 2) ในคำตอบหน้าเว็บที่ใช้การคำนวณก่อนหน้านี้จะถูกดาวน์โหลด ตัวอย่างเช่นนี่อาจเป็นหน้าที่พิมพ์ผลลัพธ์ของตารางที่คำนวณในการโทร ajax * /
                window.location.href = DownloadPage.php + "? ID =" + 29;
            }               
       }
);

// ตัวอย่างเช่น: ใน CalculusPage.php

    ถ้า (! ว่างเปล่า ($ _ POST ["calculusFunction"])) 
    {
        $ ID = $ _POST ["ID"];

        $ query = "INSERT INTO ExamplePage (data1, data2) ค่า ('". $ _ POST ["data1"]. "', '". $ _ POST ["data2"]. "ID WHERE ID =". $ ID;
        ...
    }

// ตัวอย่างเช่น: ใน DownloadPage.php

    $ ID = $ _GET ["ID"];

    $ sede = "SELECT * จากตัวอย่างหน้า WHERE id =". $ ID;
    ...

    $ ชื่อไฟล์ = "Export_Data.xls";
    header ("ประเภทเนื้อหา: application / vnd.ms-excel");
    header ("การจัดการเนื้อหา: inline; filename = $ filename");

    ...

ฉันหวังว่าโซลูชันนี้จะมีประโยชน์สำหรับหลาย ๆ คนเช่นเดียวกับฉัน


0
The HTML Code:-

'<button type="button" id="GetFile">Get File!</button>'


The jQuery Code:-

'$('#GetFile').on('click', function () {
    $.ajax({
        url: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/172905/test.pdf',
        method: 'GET',
        xhrFields: {
            responseType: 'blob'
        },
        success: function (data) {
            var a = document.createElement('a');
            var url = window.URL.createObjectURL(data);
            a.href = url;
            a.download = 'myfile.pdf';
            document.body.append(a);
            a.click();
            a.remove();
            window.URL.revokeObjectURL(url);
        }
    });
});'

คำตอบของรหัสเท่านั้นควรมีคำอธิบายขั้นต่ำอย่างน้อยอธิบายวิธีการทำงานของรหัสและทำไมมันถึงตอบคำถาม
Roberto Caboni

0

มันทำงานได้ดีในเบราว์เซอร์ใด ๆ (ฉันใช้ asp.net หลัก)

            function onDownload() {

  const api = '@Url.Action("myaction", "mycontroller")'; 
  var form = new FormData(document.getElementById('form1'));

  fetch(api, { body: form, method: "POST"})
      .then(resp => resp.blob())
      .then(blob => {
          const url = window.URL.createObjectURL(blob);
        $('#linkdownload').attr('download', 'Attachement.zip');
          $('#linkdownload').attr("href", url);
          $('#linkdownload')
              .fadeIn(3000,
                  function() { });

      })
      .catch(() => alert('An error occurred'));



}
 
 <button type="button" onclick="onDownload()" class="btn btn-primary btn-sm">Click to Process Files</button>
 
 
 
 <a role="button" href="#" style="display: none" class="btn btn-sm btn-secondary" id="linkdownload">Click to download Attachments</a>
 
 
 <form asp-controller="mycontroller" asp-action="myaction" id="form1"></form>
 
 

        function onDownload() {
            const api = '@Url.Action("myaction", "mycontroller")'; 
            //form1 is your id form, and to get data content of form
            var form = new FormData(document.getElementById('form1'));

            fetch(api, { body: form, method: "POST"})
                .then(resp => resp.blob())
                .then(blob => {
                    const url = window.URL.createObjectURL(blob);
                    $('#linkdownload').attr('download', 'Attachments.zip');
                    $('#linkdownload').attr("href", url);
                    $('#linkdownload')
                        .fadeIn(3000,
                            function() {

                            });
                })
                .catch(() => alert('An error occurred'));                 

        }

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.