如何使用 jQuery Ajax 调用从 ASP.NET Web Api 下载 CSV 文件

Posted

技术标签:

【中文标题】如何使用 jQuery Ajax 调用从 ASP.NET Web Api 下载 CSV 文件【英文标题】:How to download CSV file from ASP.NET Web Api using jQuery Ajax call 【发布时间】:2013-02-26 08:56:06 【问题描述】:

我正在研究如何通过 jQuery ajax 调用从 ASP.NET Web Api 下载 CSV 文件。 CSV 文件是基于自定义 CsvFormatter 从 Web API 服务器动态生成的。

来自 jQuery 的 Ajax:

   $.ajax(
        type: "GET",
        headers: 
            Accept: "text/csv; charset=utf-8",
        ,
        url: "/api/employees",
        success: function (data) 
        
    );

在服务器上,EmployeeCsvFormatter 的实现与以下文章类似,源自BufferedMediaTypeFormatter

http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters

public class EmployeeCsvFormatter : BufferedMediaTypeFormatter

    public EmployeeCsvFormatter()
    
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
    
    ...

我还添加了覆盖方法来表示我想像正常下载文件一样下载(可以在下载选项卡中查看下载文件):

 public override void SetDefaultContentHeaders(Type type, 
    HttpContentHeaders headers, MediaTypeHeaderValue mediaType)       

    base.SetDefaultContentHeaders(type, headers, mediaType);
    headers.Add("Content-Disposition", "attachment; filename=yourname.csv");
    headers.ContentType =  new MediaTypeHeaderValue("application/octet-stream");

但它不起作用,下载文件没有显示在状态栏或 Chrome 的下载选项卡中,即使来自 Fiddler,我看到它的响应似乎是正确的:

HTTP/1.1 200 OK
Server: ASP.NET Development Server/11.0.0.0
Date: Mon, 11 Mar 2013 08:19:35 GMT
X-AspNet-Version: 4.0.30319
Content-Disposition: attachment; filename=yourname.csv
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: application/octet-stream
Content-Length: 26
Connection: Close

1,Cuong,123
1,Trung,123

我的 ApiController 方法:

public EmployeeDto[] Get()

    var result = new[]
               
                   new EmployeeDto() Id = 1, Name = "Cuong", Address = "123",
                   new EmployeeDto() Id = 1, Name = "Trung", Address = "123",
               ;

    return result;

它一定是我没有弄清楚的地方出错了。如何像正常方式一样通过下载 CSV 文件使其工作?

【问题讨论】:

无法使用 AJAX 下载到文件。只需将用户重定向到 url window.location=url,如果服务器强制下载他们不会离开当前页面 @charlietfl: 我怎样才能用这种方式设置 Accept 标头? 您对accept header 有什么期望?不能通过下载强制用户接受任何内容 【参考方案1】:

jQuery Plugin for Requesting Ajax-like File Downloads 在没有 Ajax 的情况下可以做到 using a simple form submit。

内部:

jQuery('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
    .appendTo('body').submit().remove()

它有一个 ajax 风格的界面,所以你可以从外面这样调用它

$.download('/api/employees','format=csv');

另一种简单的方法使用:

$('#btnDownload').click(function (e) 
    e.preventDefault();
    window.location = "/api/employees?format=csv";
);

在服务器上,MediaTypeMappings 必须通过添加一个构造函数来使用:

    public EmployeeCsvFormatter(MediaTypeMapping mediaTypeMapping)
        : this()
    
        MediaTypeMappings.Add(mediaTypeMapping);
    

然后,将此格式化程序添加到 Web Api 配置中:

   configuration.Formatters.Add(new EmployeeCsvFormatter
            (new QueryStringMapping("format", "csv", "text/csv")));

【讨论】:

这种方式如何添加Accept header? 好点。我担心浏览器会添加一个。您可以将格式放在 URL 中,例如 $.download('/api/employees/csv',''); 或作为参数:$.download('/api/employees/','format=csv'); 啊,开箱即用?有时候,生活并不像恐惧那么复杂!将更新答案。 哦,我傻了,现在我读到 queryStringMapper 是必需的。请使用适当的映射器进行更新。 如果 Get() 或 Post() 接受参数,你将如何使用 jquery 下载来适应?【参考方案2】:

作为一种替代方法,可以通过单击锚点 () 或按钮提供下载,并将请求的 URL 设置为响应附件的 API 方法。

CsvMediaTypeFormatter(Derived from System.Net.Http.Formatting.MediaTypeFormatter)中,除了如上面的答案所示映射text/csv MIME类型外,我发现还需要做以下工作:

public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
        
            base.SetDefaultContentHeaders(type, headers, mediaType);
            headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            
                FileName = string.Concat("data", DateTime.UtcNow.ToString("yyyyMMddhhmmss"), ".csv")
            ;

            headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        

注意:写流时,设置Content-Length标头,记得刷新流。我发现如果不调用Flush(),即使设置了正确的内容长度,返回的响应也不会成功返回客户端。

【讨论】:

【参考方案3】:

也可以在beforeSend中通过修改xhr来设置请求头。

    $.ajax(
    url: "/api/employees",
    type: "GET",
    beforeSend: function (xhr) 
        xhr.setRequestHeader("Accept", "text/csv");
    ,
    success: function (data) 
            
    );

【讨论】:

以上是关于如何使用 jQuery Ajax 调用从 ASP.NET Web Api 下载 CSV 文件的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 jQuery AJAX 调用 ASP.Net 字符串函数?

如何从 jQuery ajax 调用将复杂对象传递给 ASP.NET WebApi GET?

使用 jquery ajax 从 asp.net 网页表单页面调用 web api url

如何使用 ASP.NET MVC Rest API 调用和 jQuery Ajax 下载文件

如何在asp.net mvc中使用jquery ajax在方法中调用字符串

使用 Jquery AJAX 从 ASP.NET Web 服务器获取对象