zoukankan      html  css  js  c++  java
  • aspnetcore 实现断点续传

    扩展方法

            /// <summary>
            /// 断点下载
            /// </summary>
            /// <param name="controller"></param>
            /// <param name="fullpath"></param>
            /// <returns></returns>
            public static async Task<long> RangeDownload(this Controller controller, string fullpath)
            {
                long size, start, end, length, fp = 0;
                using (StreamReader reader = new StreamReader(File.OpenRead(fullpath)))
                {
    
                    size = reader.BaseStream.Length;
                    start = 0;
                    end = size - 1;
                    length = size;
                    // Now that we‘ve gotten so far without errors we send the accept range header
                    /* At the moment we only support single ranges.
                     * Multiple ranges requires some more work to ensure it works correctly
                     * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
                     *
                     * Multirange support annouces itself with:
                     * header(‘Accept-Ranges: bytes‘);
                     *
                     * Multirange content must be sent with multipart/byteranges mediatype,
                     * (mediatype = mimetype)
                     * as well as a boundry header to indicate the various chunks of data.
                     */
                    controller.Response.Headers.Add("Accept-Ranges", "0-" + size);
                    // header(‘Accept-Ranges: bytes‘);
                    // multipart/byteranges
                    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
    
                    if (!String.IsNullOrEmpty(controller.Request.Headers["HTTP_RANGE"]))
                    {
                        long anotherStart = start;
                        long anotherEnd = end;
                        string[] arr_split = controller.Request.Headers["HTTP_RANGE"].FirstOrDefault().Split(new char[] { Convert.ToChar("=") });
                        string range = arr_split[1];
    
                        // Make sure the client hasn‘t sent us a multibyte range
                        if (range.IndexOf(",") > -1)
                        {
                            // (?) Shoud this be issued here, or should the first
                            // range be used? Or should the header be ignored and
                            // we output the whole content?
                            controller.Response.Headers.Add("Content-Range", "bytes " + start + "-" + end + "/" + size);
                            controller.Response.StatusCode = 416;
                            controller.Response.StatusCode = 416;
                            await controller.Response.WriteAsync("Requested Range Not Satisfiable");
                        }
    
                        // If the range starts with an ‘-‘ we start from the beginning
                        // If not, we forward the file pointer
                        // And make sure to get the end byte if spesified
                        if (range.StartsWith("-"))
                        {
                            // The n-number of the last bytes is requested
                            anotherStart = size - Convert.ToInt64(range.Substring(1));
                        }
                        else
                        {
                            arr_split = range.Split(new char[] { Convert.ToChar("-") });
                            anotherStart = Convert.ToInt64(arr_split[0]);
                            long temp = 0;
                            anotherEnd = (arr_split.Length > 1 && Int64.TryParse(arr_split[1].ToString(), out temp)) ? Convert.ToInt64(arr_split[1]) : size;
                        }
                        /* Check the range and make sure it‘s treated according to the specs.
                         * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
                         */
                        // End bytes can not be larger than $end.
                        anotherEnd = (anotherEnd > end) ? end : anotherEnd;
                        // Validate the requested range and return an error if it‘s not correct.
                        if (anotherStart > anotherEnd || anotherStart > size - 1 || anotherEnd >= size)
                        {
    
                            controller.Response.Headers.Add("Content-Range", "bytes " + start + "-" + end + "/" + size);
                            controller.Response.StatusCode = 416;
                            await controller.Response.WriteAsync( "Requested Range Not Satisfiable");
                        }
                        start = anotherStart;
                        end = anotherEnd;
    
                        length = end - start + 1; // Calculate new content length
                        fp = reader.BaseStream.Seek(start, SeekOrigin.Begin);
                        controller.Response.StatusCode = 206;
                    }
                }
                // Notify the client the byte range we‘ll be outputting
                controller.Response.Headers.Add("Content-Range", "bytes " + start + "-" + end + "/" + size);
                controller.Response.Headers.Add("Content-Length", length.ToString());
                // Start buffered download
                await controller.Response.SendFileAsync(fullpath, fp, length);
                return fp;
            }        

    控制器方法内调用样例:

            /// <summary>
            /// 下载指定版本
            /// </summary>
            /// <param name="id"></param>
            /// <param name="version"></param>
            /// <returns></returns>
            public async Task Download(Guid id, int version)
            {
                string path = null;
                var state = appService.GetAppState(id, version);
                if (state == Model.AppState.Available)
                {
                    path = appService.GetZipFromAppList(id, version);
                    if (!System.IO.File.Exists(path))
                    {
                        await this.StatusCode(404).ExecuteResultAsync(this.ControllerContext);
                    }
                    var offset = await this.RangeDownload(path);
                    if (offset == 0)
                    {
                        appService.IncreaseNDownload(state, id, version);
                    }
                }
                else
                {
                    await this.StatusCode(404).ExecuteResultAsync(this.ControllerContext);
                }
        }
  • 相关阅读:
    spring scope 属性的取值
    DefaultTransactionStatus源码
    Spring事务管理接口PlatformTransactionManager的实现类DataSourceTransactionManager
    Spring 框架简介
    PL/SQL游标
    [BC冠军赛(online)]小结
    [hdu5164]ac自动机
    [hdu2222]ac自动机(模板)
    上浮法或漂浮法
    [hdu5213]容斥原理+莫队算法
  • 原文地址:https://www.cnblogs.com/kevin860/p/12650625.html
Copyright © 2011-2022 走看看