You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Grails中通过Ajax调用控制器实现文件下载的问题

Fixing File Download in Grails for Your Export Feature

Hey there! I see you're new to Grails and stuck on getting that file download working after triggering it with jQuery. Let's break down the problem and fix it step by step.

Why Your Current Code Isn't Working

The issue here is that AJAX requests don't automatically trigger browser file downloads. When you send an AJAX POST, the browser handles the response in the background, but it won't pop up the download dialog for file streams. We need to adjust how we send the request so the browser knows to handle the response as a downloadable file.

Solution 1: Use a Hidden Form Instead of AJAX

This is the simplest approach for your scenario. We'll create a hidden form dynamically, populate it with your data, and submit it—this tells the browser to expect a file download response.

Updated jQuery Code

$("#exportAllSelectedData").click(function() { 
    var dataToExport = $("#dataToExport").val(); 

    // Create a hidden form to submit our data
    const exportForm = $('<form>', {
        method: 'POST',
        action: '/myapp/mycontroller/exportPreferences'
    });

    // Add our data as a hidden input field
    $('<input>', {
        type: 'hidden',
        name: 'dataToExport',
        value: dataToExport
    }).appendTo(exportForm);

    // Append form to the page and submit it
    exportForm.appendTo('body').submit();
});

Complete Grails Controller Code

You don't even need a temporary file—we can write the data directly to the response stream, which is more efficient. Here's how to set up the response headers to trigger the download:

def exportPreferences() { 
    String dataToWrite = params.dataToExport

    // Set response headers to tell browser this is a downloadable XML file
    response.contentType = 'application/xml'
    response.setHeader('Content-Disposition', 'attachment; filename="exported_preferences.xml"')

    // Write the data directly to the response stream
    response.outputStream << dataToWrite
    response.outputStream.flush()
    response.outputStream.close()

    // No need to return anything—we've handled the response directly
    return null
}

Solution 2: If You Really Need AJAX (Optional)

If you must use AJAX (for example, if you need to validate data first), you can have the controller return a URL to a download endpoint, then trigger the download via window.open() or location.href. This requires storing the data temporarily (like in the session) so the download endpoint can access it:

Controller (Two Actions)

def prepareExport() {
    String dataToWrite = params.dataToExport
    session.exportData = dataToWrite // Store data in session
    render([downloadUrl: createLink(action: 'downloadExport')] as JSON)
}

def downloadExport() {
    String dataToWrite = session.removeAttribute('exportData') // Clean up session
    if (!dataToWrite) {
        render status: 404, text: 'No export data found'
        return
    }

    // Same response setup as before
    response.contentType = 'application/xml'
    response.setHeader('Content-Disposition', 'attachment; filename="exported_preferences.xml"')
    response.outputStream << dataToWrite
    response.outputStream.flush()
    response.outputStream.close()
    return null
}

Updated jQuery for AJAX Approach

$("#exportAllSelectedData").click(function() { 
    var dataToExport = $("#dataToExport").val(); 

    $.ajax({
        type: 'POST',
        data: { dataToExport: dataToExport },
        dataType: 'json',
        url: '/myapp/mycontroller/prepareExport',
        success: function(response) {
            // Trigger download using the returned URL
            window.open(response.downloadUrl, '_self');
        }
    });
});

Final Notes

  • The first solution is recommended for your use case—it's simpler and avoids session storage overhead.
  • Always set the correct contentType (here application/xml) so the browser knows how to handle the file.
  • The Content-Disposition header tells the browser to treat the response as an attachment and sets the default filename.

内容的提问来源于stack exchange,提问作者Samos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:35:21