H5+Ajax+WebApi实现文件下载(进度条,多文件)

前言

 

踩过的坑


1、WebAPI跨域

2、Jquery ajax低版本不支持XHR 2功能

3、Jquery ajax不支持Deferred的process事件

4、IE下文件名乱码问题

功能实现

 

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <meta charset="utf-8" />
    <script src="https://code.jquery.com/jquery-3.2.1.min.js

"></script>
</head>
<body>
    <input type="button" value="全部下载" onclick="doAllDownload()" />
    <div>
        <ul>
            <li>
                <span>文件1.txt</span>&nbsp;&nbsp;<span id="progress1"></span>
            </li>
            <li>
                <span>文件2.txt</span>&nbsp;&nbsp;<span id="progress2"></span>
            </li>
            <li>
                <span>文件3.txt</span>&nbsp;&nbsp;<span id="progress3"></span>
            </li>
        </ul>
    </div>
    <script>
        function doAllDownload() {
            /**
            测试:
            1、文件3数据量大
            2、文件2不存在
            **/
            var files = [];
            files.push({ url: 'D:\\Test\\1.txt', id: 'progress1' });
            files.push({ url: 'D:\\Test\\2.txt', id: 'progress2' });
            files.push({ url: 'D:\\Test\\3.txt', id: 'progress3' });
            files.forEach(function (item) {
                //多文件下载
                DownloadFile(item.url).then(function (result) {
                    //请求完成
                    var msg = "文件下载完毕!";
                    if (result.error) {
                        msg = result.error.message ? result.error.message : "文件下载错误!";
                    }
                    $("#" + item.id).html(msg);
                }, function (err) { }, function (evt) {
                    //根据item处理进度条数据
                    $("#" + item.id).html("已下载 " + parseInt(100 * evt.loaded / evt.total) + "%");
                });
            })
        }
        function DownloadFile(url) {
            var filename = url.substr(url.lastIndexOf('\\') + 1);//文件名
            var dfd = new $.Deferred();
            var promise = $.ajax("http://localhost:2032/api/Test/DownloadFileUrl", {
                type: "POST",
                contentType: 'application/json',
                data: JSON.stringify({ url: url }),
                /*JQuery 3.0以下版本不支持*/
                xhrFields: {
                    responseType: 'arraybuffer',
                    onprogress: dfd.notify//触发dfd.process事件
                }
            });
            promise.then(function (data, status, xhr) {
                if (xhr.statusText == "OK") {
                    var type = xhr.getResponseHeader('Content-Type');
                    var blob = new Blob([data], { type: type });
                    if (typeof window.navigator.msSaveBlob !== 'undefined') {
                        window.navigator.msSaveBlob(blob, filename);
                    } else {
                        var URL = window.URL || window.webkitURL;
                        var downloadUrl = URL.createObjectURL(blob);
                        if (filename) {
                            var a = document.createElement("a");
                            if (typeof a.download === 'undefined') {
                                window.location = downloadUrl;
                            } else {
                                a.href = downloadUrl;
                                a.download = filename;
                                document.body.appendChild(a);
                                a.click();
                            }
                        } else {
                            window.location = downloadUrl;
                        }

                        setTimeout(function () {
                            URL.revokeObjectURL(downloadUrl);
                            dfd.resolve({});
                        }, 100);
                    }
                } else {
                    dfd.resolve({ error: { message: xhr.statusText } });
                }
            }, function (err) {
                //异常处理
            }, function (info) {
                //不支持Deferred的process事件
            });
            return dfd;
        }
    </script>
</body>
</html>

 

Asp.NET后台代码

 

1、为了设置进度条 故设置 BUFFER_SIZE 为 5 开发时请注意,跨域设置请自行在Web.config或者WebApiConfig.cs里面设置。就不上代码了,网上很多例子!
2、文件名乱码问题:请参考 https://my.oschina.net/pingpangkuangmo/blog/376332

 

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Http;

namespace WebAPI.Controllers
{
    public class TestController:ApiController
    {
        private const int BUFFER_SIZE = 5;
        [HttpPost]
        public void DownloadFileUrl(dynamic args)
        {
            string url = args.url;
            string filename = url.Substring(url.LastIndexOf('\\') + 1);
            var response = HttpContext.Current.Response;
            if (File.Exists(url))
            {
                byte[] buffer = new byte[BUFFER_SIZE];
                response.Clear();
                //跨域处理
                response.AddHeader("Access-Control-Allow-Origin", "*");//支持所有跨域请求
                response.AddHeader("Access-Control-Allow-Headers", "*");//支持所有Access-Control-Request-Headers字段

                response.ContentType = "application/octet-stream";//定义stream为下载类型的窗口
                response.AddHeader("Content-Disposition", "attachment;filename=" + filename);
                using (var stream = File.Open(url, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    //CORS请求时可访问 Content-Length
                    var sHeaders = response.Headers["Access-Control-Expose-Headers"] + ",Content-Length";
                    response.Headers.Remove("Access-Control-Expose-Headers");
                    response.AddHeader("Access-Control-Expose-Headers", sHeaders);

                    long total = stream.Length;//文件总大小
                    response.AddHeader("Content-Length", total.ToString());
                    response.Charset = "UTF-8";
                    while (total > 0 && response.IsClientConnected)
                    {
                        int read = stream.Read(buffer, 0, BUFFER_SIZE);//读取的大小
                        response.OutputStream.Write(buffer, 0, read);
                        response.Flush();
                        total = total - read;
                    }
                    response.End();
                }
            }
            else
            {
                response.Clear();
                response.AddHeader("Access-Control-Allow-Origin", "*");//支持所有跨域请求
                response.AddHeader("Access-Control-Allow-Headers", "*");//支持所有Access-Control-Request-Headers字段
                response.StatusCode = 200;
                response.Status = "200 File_Not_Found";
                response.Write("{\"Message\":\"File Not Found\",\"Status\":\"ERROR\"}");
                response.End();
            }
        }
        
    }
}

测试结果:
文件准备 D:\\Test\1.txt(数据过多) D:\\Test\3.txt(数据略少) 两个文件,文件 2.txt 不存在。

转载于:https://www.cnblogs.com/yanJP/p/7280331.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常精美的h5 进度条 |DEMO_jQuery之家-自由分享jQuery、html5、css3的插件库 <!----> .ClassyCountdownDemo { margin:0 auto 30px auto; max-width:800px; width:calc(100%); padding:30px; display:block } #countdown2 { background:#FFF } #countdown3 { background:rgb(52, 73, 94) } #countdown4 { background:#222 } #countdown5 { background:#222 } #countdown6 { background:#222 } #countdown7 { background:#222 } #countdown8 { background:#222 } #countdown9 { background:#FFF } #countdown10 { background:#3498db } jQuery炫酷图片预览Lightbox插件 A jQuery plugin designed to provide gallery view for images jQuery之家 返回下载页 Example $(document).ready(function() { $('#countdown15').ClassyCountdown({ theme: "flat-colors", end: $.now() + 10000 }); $('#countdown16').ClassyCountdown({ theme: "flat-colors-wide", end: $.now() + 10000 }); $('#countdown17').ClassyCountdown({ theme: "flat-colors-very-wide", end: $.now() + 10000 }); $('#countdown18').ClassyCountdown({ theme: "flat-colors-black", end: $.now() + 10000 }); $('#countdown1').ClassyCountdown({ theme: "white", end: $.now() + 645600 }); $('#countdown5').ClassyCountdown({ theme: "white", end: $.now() + 10000 }); $('#countdown6').ClassyCountdown({ theme: "white-wide", end: $.now() + 10000 }); $('#countdown7').ClassyCountdown({ theme: "white-very-wide", end: $.now() + 10000 }); $('#countdown8').ClassyCountdown({ theme: "white-black", end: $.now() + 10000 }); $('#countdown11').ClassyCountdown({ theme: "black", style: { secondsElement: { gauge: { fgColor: "#F00" } } }, end: $.now() + 10000 }); $('#countdown12').ClassyCountdown({ theme: "black-wide", labels: false, end: $.now() + 10000 }); $('#countdown13').ClassyCountdown({ theme: "black-very-wide", labelsOptions: { lang: { days: 'D', hours: 'H', minutes: 'M', seconds: 'S' }, style: 'font-size:0.5em; text-transform:uppercase;' }, end: $.now() + 10000 }); $('#countdown14').ClassyCountdown({ theme: "black-black", labelsOptions: { style: 'font-size:0.5em; text-transform:uppercase;' }, end: $.now() + 10000 }); $('#countdown4').ClassyCountdown({ end: $.now() + 10000, labels: true, style: { element: "", textResponsive: .5, days: { gauge: { thickness: .03, bgColor: "rgba(255,255,255,0.05)", fgColor: "#1abc9c" }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:#fff;' }, hours: { gauge: { thickness: .03, bgColor: "rgba(255,255,255,0.05)", fgColor: "#2980b9" }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:#fff;' }, minutes: { gauge: { thickness: .03, bgColor: "rgba(255,255,255,0.05)", fgColor: "#8e44ad" }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:#fff;' }, seconds: { gauge: { thickness: .03, bgColor: "rgba(255,255,255,0.05)", fgColor: "#f39c12" }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:#fff;' } }, onEndCallback: function() { console.log("Time out!"); } }); $('#countdown2').ClassyCountdown({ end: '1388468325', now: '1378441323', labels: true, style: { element: "", textResponsive: .5, days: { gauge: { thickness: .01, bgColor: "rgba(0,0,0,0.05)", fgColor: "#1abc9c" }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:#34495e;' }, hours: { gauge: { thickness: .01, bgColor: "rgba(0,0,0,0.05)", fgColor: "#2980b9" }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:#34495e;' }, minutes: { gauge: { thickness: .01, bgColor: "rgba(0,0,0,0.05)", fgColor: "#8e44ad" }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:#34495e;' }, seconds: { gauge: { thickness: .01, bgColor: "rgba(0,0,0,0.05)", fgColor: "#f39c12" }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:#34495e;' } }, onEndCallback: function() { console.log("Time out!"); } }); $('#countdown9').ClassyCountdown({ end: '1388468325', now: '1380501323', labels: true, style: { element: "", textResponsive: .5, days: { gauge: { thickness: .05, bgColor: "rgba(0,0,0,0)", fgColor: "#1abc9c", lineCap: 'round' }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:#34495e;' }, hours: { gauge: { thickness: .05, bgColor: "rgba(0,0,0,0)", fgColor: "#2980b9", lineCap: 'round' }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:#34495e;' }, minutes: { gauge: { thickness: .05, bgColor: "rgba(0,0,0,0)", fgColor: "#8e44ad", lineCap: 'round' }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:#34495e;' }, seconds: { gauge: { thickness: .05, bgColor: "rgba(0,0,0,0)", fgColor: "#f39c12", lineCap: 'round' }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:#34495e;' } }, onEndCallback: function() { console.log("Time out!"); } }); $('#countdown10').ClassyCountdown({ end: '1397468325', now: '1388471324', labels: true, labelsOptions: { lang: { days: 'D', hours: 'H', minutes: 'M', seconds: 'S' }, style: 'font-size:0.5em; text-transform:uppercase;' }, style: { element: "", textResponsive: .5, days: { gauge: { thickness: .02, bgColor: "rgba(255,255,255,0.1)", fgColor: "rgba(255,255,255,1)", lineCap: 'round' }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:rgba(255,255,255,0.7);' }, hours: { gauge: { thickness: .02, bgColor: "rgba(255,255,255,0.1)", fgColor: "rgba(255,255,255,1)", lineCap: 'round' }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:rgba(255,255,255,0.7);' }, minutes: { gauge: { thickness: .02, bgColor: "rgba(255,255,255,0.1)", fgColor: "rgba(255,255,255,1)", lineCap: 'round' }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:rgba(255,255,255,0.7);' }, seconds: { gauge: { thickness: .02, bgColor: "rgba(255,255,255,0.1)", fgColor: "rgba(255,255,255,1)", lineCap: 'round' }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:rgba(255,255,255,0.7);' }, }, onEndCallback: function() { console.log("Time out!"); } }); $('#countdown3').ClassyCountdown({ end: '1390868325', now: '1388461323', labels: true, labelsOptions: { lang: { days: 'Zile', hours: 'Ore', minutes: 'Minute', seconds: 'Secunde' }, style: 'font-size:0.5em; text-transform:uppercase;' }, style: { element: "", textResponsive: .5, days: { gauge: { thickness: .2, bgColor: "rgba(255,255,255,0.2)", fgColor: "rgb(241, 196, 15)" }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:rgba(255,255,255,0.7);' }, hours: { gauge: { thickness: .2, bgColor: "rgba(255,255,255,0.2)", fgColor: "rgb(241, 196, 15)" }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:rgba(255,255,255,0.7);' }, minutes: { gauge: { thickness: .2, bgColor: "rgba(255,255,255,0.2)", fgColor: "rgb(241, 196, 15)" }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:rgba(255,255,255,0.7);' }, seconds: { gauge: { thickness: .2, bgColor: "rgba(255,255,255,0.2)", fgColor: "rgb(241, 196, 15)" }, textCSS: 'font-family:\'Open Sans\'; font-size:25px; font-weight:300; color:rgba(255,255,255,0.7);' } }, onEndCallback: function() { console.log("Time out!"); } }); }); 如果你喜欢这个插件,那么你可能也喜欢: html5+jquery通过鼠标控制的圆形进度条 jQuery和css3旋钮控制按钮-knobKnob
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值