基于ASP.NET Webapi和ajax技术且兼容Chrome、Firefox和IE浏览器的Excel文件下载方法

这个假期都在做一个综合ASP.NET MVC、Webapi、jquery、ajax、easyui等技术和框架的高速公路大数据分析网站项目。系统用json做前后端通信的数据格式,后端主要用Webapi处理业务逻辑,并返回一个定制的消息对象,前端就是jquery、ajax和easyui等呈现和相关处理。

前面的文件上传、参数传递、CRUD操作、数据集合返回给easyui等都做得十分顺利。最后,要输出报表了。使用NPOI组件在后端生成一个Excel报表,然后像image处理一样转换成base64字符串格式,通过Webapi返回给前端浏览器。Chrome和Firefox均能很好地支持直接在浏览器里打开下载窗口,见如下代码:

    function DownloadFile(xlsBase64)  
    {
        if (!document.getElementById("dwnf"))
        {
            $(document.body).append('<a href="#" id="dwnf" style="display: none"></a>');
        }

        var reportName = $('#ReportNames').val();
        var fileName =  reportName + '_' + GetPeriodNo() + '.xls';
        var url = 'data:application/vnd.ms-excel;base64,' + xlsBase64;

        document.getElementById("dwnf").href = url;
        document.getElementById("dwnf").download = fileName;
        document.getElementById("dwnf").click();

        $('#dwnf').remove();
    }
上面代码中,xlsBase64就是Excel文件转换成的base64字符串。

自己测试和网上公开的资料表明,Windows10自带的IE11和Edge均不支持data:base64的Excel文件下载(奇怪的是,IE支持image的base64格式显示!)。显然,得 再找其他处理方法了。

在后端下载一个文件,不管是用控制器还是Webapi,主要代码如下:

        [HttpGet]
        public HttpResponseMessage Download(string id)
        {
            HttpResponseMessage response = new HttpResponseMessage();

            object xlsObj = this.MyCache.Get(id);

            if (xlsObj == null)
            {
                response.StatusCode = System.Net.HttpStatusCode.NotFound;
                return response;
            }

            TXlsFileStream xlsFile = xlsObj as TXlsFileStream;
            response.Content = new StreamContent(xlsFile.XlsFileStream);
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            response.Content.Headers.ContentDisposition.FileName = xlsFile.FileName;
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");  // 这句话要告诉浏览器要下载文件  
            return response;
        }
    }
上述代码中,XlsFileStream为一个MemoryStream,该流接收NPOI的Wookbook对象中的流数据(Wookbook可以直接Save到MemoryStream中),注意,其Position必须为0。

问题是,系统传输均是json格式数据,前端使用jquery的ajax,直接调用ajax将返回不正确的信息或其他异常结果,不会打开一个文件下载窗口。经过多次尝试,最后的解决方法是做两次请求访问:

  1. 第一次使用ajax,传递相关参数、请求一个报表文件,并在Cache中保留Excel文件流;
  2. 第二次,是在第一ajax结果返回后,如果success,则直接调用下面模拟<a>下载的脚本代码:
   function Download(url, fileName)
   {
        if (!document.getElementById('dwnf'))
        {
            $(document.body).append('<a href="#" id="dwnf" style="display: none"></a>');
        }

        document.getElementById('dwnf').href = url;
        document.getElementById('dwnf').download = fileName;
        document.getElementById('dwnf').click();

        $('#dwnf').remove();
   }
上面函数中,url的字符串是Webapi的一般调用格式,如../Api/FileApi/Download?id=..。注意,不能省略临时创建的<a>的.download属性,否则IE时将获得不正确的格式(Chrome和Firefox可以省略这个.download = filename的属性赋值语句)。

获得的体验就是,为了兼容IE,需要多花好多的时间、多伤好多的神!另一个收获是,办法总比困难多!


猜你喜欢

转载自blog.csdn.net/hulihui/article/details/77478868