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

如何通过Ajax调用WebService函数,实现DataTable按钮触发PDF下载

解决Ajax调用WebService下载PDF的问题

首先得明确:Ajax本身没法直接触发浏览器的文件下载弹窗,因为Ajax请求的响应会被JS引擎接管,而不是交给浏览器处理下载行为。不过我们有几种实用的替代方案,能实现点击DataTable按钮下载数据库中PDF的需求,下面一步步拆解:

方案1:直接跳转WebService地址(最简单高效)

如果你的WebService允许GET请求,直接通过按钮点击跳转至WebService接口,浏览器会自动处理下载逻辑:

第一步:调整WebMethod支持GET(可选)

默认WebMethod是POST请求,若要支持GET,添加[ScriptMethod(UseHttpGet = true)]特性,同时修改参数获取方式:

[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public void DownloadFile(string id)
{
    byte[] bytes;
    string contentType;
    string fileName;

    // 从数据库根据id读取文件数据、类型、文件名
    using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["YourConnString"].ConnectionString))
    {
        using (SqlCommand cmd = new SqlCommand("SELECT FileData, ContentType, FileName FROM Files WHERE Id = @Id", con))
        {
            cmd.Parameters.AddWithValue("@Id", id);
            con.Open();
            using (SqlDataReader dr = cmd.ExecuteReader())
            {
                if (dr.Read())
                {
                    bytes = (byte[])dr["FileData"];
                    contentType = dr["ContentType"].ToString();
                    fileName = dr["FileName"].ToString();
                }
                else
                {
                    HttpContext.Current.Response.StatusCode = 404;
                    return;
                }
            }
        }
    }

    // 输出文件响应头与内容
    HttpContext.Current.Response.Clear();
    HttpContext.Current.Response.ContentType = contentType;
    HttpContext.Current.Response.AddHeader("Content-Disposition", $"attachment; filename={fileName}");
    HttpContext.Current.Response.BinaryWrite(bytes);
    HttpContext.Current.Response.Flush();
    HttpContext.Current.Response.End();
}

第二步:DataTable按钮绑定跳转逻辑

在DataTable的列渲染中生成按钮,并绑定点击事件:

$('#yourDataTable').DataTable({
    columns: [
        // 其他列配置...
        {
            data: 'id',
            render: function(data, type, row) {
                return `<button class="download-btn" data-id="${data}">下载PDF</button>`;
            }
        }
    ]
});

// 全局绑定按钮点击事件
$(document).on('click', '.download-btn', function() {
    const fileId = $(this).data('id');
    // 直接跳转至WebService接口,浏览器自动触发下载
    window.location.href = `YourWebService.asmx/DownloadFile?id=${fileId}`;
});

方案2:用隐藏表单提交(适合POST请求场景)

如果必须用POST请求(比如id长度较长或有安全需求),可以通过动态创建隐藏表单提交参数:

$(document).on('click', '.download-btn', function() {
    const fileId = $(this).data('id');
    
    // 创建隐藏表单
    const form = $('<form>', {
        method: 'POST',
        action: 'YourWebService.asmx/DownloadFile'
    });
    
    // 添加id参数
    form.append($('<input>', {
        type: 'hidden',
        name: 'id',
        value: fileId
    }));
    
    // 提交表单并移除
    form.appendTo('body').submit().remove();
});

方案3:用Blob处理二进制响应(现代浏览器专属)

如果坚持要用Ajax接收响应,可以将返回的二进制数据转换为Blob,再创建下载链接:

第一步:修改WebMethod返回文件信息

把void返回改为自定义的文件信息对象,方便前端解析:

[WebMethod]
public FileInfo DownloadFile(string id)
{
    byte[] bytes;
    string contentType;
    string fileName;

    // 数据库查询逻辑同方案1...

    return new FileInfo {
        FileBytes = bytes,
        ContentType = contentType,
        FileName = fileName
    };
}

// 辅助类定义
public class FileInfo {
    public byte[] FileBytes { get; set; }
    public string ContentType { get; set; }
    public string FileName { get; set; }
}

第二步:Ajax请求并处理Blob

$(document).on('click', '.download-btn', function() {
    const fileId = $(this).data('id');
    
    $.ajax({
        url: 'YourWebService.asmx/DownloadFile',
        method: 'POST',
        contentType: 'application/json; charset=utf-8',
        data: JSON.stringify({ id: fileId }),
        dataType: 'json',
        success: function(response) {
            // 将base64编码的字节数组转换为Uint8Array
            const byteCharacters = atob(response.d.FileBytes);
            const byteNumbers = new Array(byteCharacters.length);
            for (let i = 0; i < byteCharacters.length; i++) {
                byteNumbers[i] = byteCharacters.charCodeAt(i);
            }
            const byteArray = new Uint8Array(byteNumbers);
            
            // 创建Blob并生成下载链接
            const blob = new Blob([byteArray], { type: response.d.ContentType });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = response.d.FileName;
            document.body.appendChild(a);
            a.click();
            
            // 清理资源
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        },
        error: function(xhr) {
            alert('下载失败:' + xhr.responseText);
        }
    });
});

关键注意事项

  • 响应头配置:方案1/2中,WebMethod必须正确设置Content-Disposition和ContentType,否则浏览器无法识别为可下载文件。
  • 资源泄漏:数据库操作务必用using包裹SqlConnection、SqlCommand等对象,避免连接泄漏。
  • 跨域问题:若页面与WebService不在同一域名,需配置CORS规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:31:55