一、Http的Range请求头,结合相应头Accept-Ranges、Content-Range 可以实现如下功能:

1.断点续传。用于下载文件被中断后,继续下载。

2.大文件指定区块下载,如视频、音频拖动播放,直接定位到指定位置下载内容。可以避免每次都读取、传输整个文件,从而提升服务端性能。

3.大文件分包批量下载,再合并完整文件。可以提高下载速度。

二、Http的Range 相关说明:

1.规则要点

请求头Range表示请求的数据起始位置。响应头Accept-Ranges:bytes 表示支持续传。响应头Content-Range表示返回的其实位置、总长度

请求头Range的数字,首尾都包含,长度是: end-begin+1

请求头Range的指定的长度,只是意向下载量,服务端不一定返回请求的长度。比如:bytes=0-, 表示希望下载整个文件,但服务端可以返回有限长度的数据块(有利于性能)。但数据其实位置start需按照请求。

2.在Http 响应请求是 200,表示响应结束,响应成功

Http 响应状态:206,表示响应中,响应部分数据,不会单开Socket链接。

三、在Asp.Net Core中实现自定义 Range 文件响应

1.封装处理的类:

    public class DownloadRange
{ public HttpContext context = null;
public HttpRequest request = null;
public HttpResponse response = null;
public DownloadRange(HttpContext ctx)
{
this.context = ctx;
this.request = ctx.Request;
this.response = ctx.Response;
}
private int HttpRangeSize = 1024 * 1024; //最大块长度 1M
public void WriteFile(string file)
{
using (var fs = File.OpenRead(file))
{
WriteStream(fs);
}
}
private void WriteStream(Stream fs)
{
string range = request.Headers["Range"];
range = range ?? "";
range = range.Trim().ToLower();
if (fs.CanSeek)
{
if (range.StartsWith("bytes=") && range.Contains("-"))
{
//分段输出文件
int start = -1, end = -1;
var rgs = range.Substring(6).Split('-');
int.TryParse(rgs[0], out start);
int.TryParse(rgs[1], out end);
if (rgs[0] == "")
{
start = (int)fs.Length - end;
end = (int)fs.Length - 1;
}
if (rgs[1] == "")
{
end = (int)fs.Length - 1;
}
WriteRangeStream(fs, start, end);
}
else
{
//输出整个文件
int l;
byte[] buffer = new byte[40960];
while ((l = fs.Read(buffer, 0, buffer.Length)) > 0)
{
response.Body.Write(buffer, 0, l);
}
}
}
}
private void WriteRangeStream(Stream fs, int start, int end)
{
using (fs)
{
int rangLen = end - start + 1;
if (rangLen > 0)
{
if (rangLen > HttpRangeSize)
{
rangLen = HttpRangeSize;
end = start + HttpRangeSize - 1;
}
}
else
{
throw new Exception("Range error");
} long size = fs.Length;
//如果是整个文件返回200,否则返回206
if (start == 0 && end + 1 >= size)
{
response.StatusCode = 200;
}
else
{
response.StatusCode = 206;
}
// response.Headers.Add("Accept-Ranges", "bytes");
response.Headers.Add("Content-Range", $"bytes {start}-{end}/{size}");
response.Headers.Add("Content-Length", rangLen.ToString()); int readLen, total = 0;
byte[] buffer = new byte[40960];
//流定位到指定位置
try
{
fs.Seek(start, SeekOrigin.Begin);
while (total < rangLen && (readLen = fs.Read(buffer, 0, buffer.Length)) > 0)
{
total += readLen;
if (total > rangLen)
{
readLen -= (total - rangLen);
total = rangLen;
}
response.Body.Write(buffer, 0, readLen);
}
}
catch (Exception ex)
{
throw ex;
}
}
}
}

2.自定义中间件,处理文件输出

    public class OuterImgMiddleware
{
public static string RootPath { get; set; } //配置文件读取绝对位置
private readonly RequestDelegate _next;
public OuterImgMiddleware(RequestDelegate next, Microsoft.AspNetCore.Hosting.IHostingEnvironment env)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var path = context.Request.Path.ToString();
var headersDictionary = context.Request.Headers; if (context.Request.Method == "GET" && !string.IsNullOrEmpty(path))
{
if (
path.Contains("/upload/logo")
|| path.Contains("/upload/image")
|| path.Contains("/upload/ueimage")
)
{
var unauthorizedImagePath = RootPath + path;
FileInfo file = new FileInfo(unauthorizedImagePath);
if (file.Exists)
{
int length = path.LastIndexOf(".") - path.LastIndexOf("/") - 1;
context.Response.Headers["Etag"] = path.Substring(path.LastIndexOf("/") + 1, length);
context.Response.Headers["Last-Modified"] = new DateTime(2018).ToString("r");
context.Response.Headers["Accept-Ranges"] = "bytes";
//context.Response.Headers["Content-Length"] = file.Length.ToString();
if (path.EndsWith(".mp4"))
{
context.Response.ContentType = "video/mp4";
//分段读取内容
DownloadRange download = new DownloadRange(context);
download.WriteFile(unauthorizedImagePath);
}
else
{
context.Response.ContentType = "image/jpeg";
context.Response.Headers["Cache-Control"] = "public"; //指定客户端,服务器都处理缓存
await context.Response.SendFileAsync(unauthorizedImagePath);
}
}
return;
}
} await _next(context);
}
}
public static class MvcExtensions
{
public static IApplicationBuilder UseOutImg(this IApplicationBuilder builder)
{
return builder.UseMiddleware<OuterImgMiddleware>();
}
}

3. 在服务配置中 ConfigureServices,开启同步读取

          //启用允许同步读取
services.Configure<KestrelServerOptions>(x => x.AllowSynchronousIO = true)
.Configure<IISServerOptions>(x => x.AllowSynchronousIO = true);

4.在配置中 Configure,启用中间件

app.UseOutImg();

更多:

EF Core Sequence contains no elements

.Net Core3 新特性整理

.Net Core 实现 自定义Http的Range输出实现断点续传或者分段下载的更多相关文章

  1. ASP.NET Core MVC – 自定义 Tag Helpers

    ASP.NET Core Tag Helpers系列目录,共四篇: ASP.NET Core MVC Tag Helpers 介绍 ASP.NET Core MVC – Caching Tag Hel ...

  2. 如何在ASP.NET Core中自定义Azure Storage File Provider

    文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...

  3. ASP.NET Core Identity自定义数据库结构和完全使用Dapper而非EntityFramework Core

    前言 原本本节内容是不存在的,出于有几个人问到了我:我想使用ASP.NET Core Identity,但是我又不想使用默认生成的数据库表,想自定义一套,我想要使用ASP.NE Core Identi ...

  4. .Net Core IIS下无Log4Net日志输出,命令行下却有(dotnet运行)

    .Net Core IIS下无Log4Net日志输出,命令行下却有(dotnet运行) 遇到个诡异的问题,项目发布并寄宿到 IIS上后,Log4Net没有日志输出 1.原因分析 这不应该啊,所有的配置 ...

  5. ASP.NET Core AutoWrapper 自定义响应输出

    前言 AutoWrapper是一个简单可自定义全局异常处理程序和ASP.NET Core API响应的包装.他使用ASP.NET Core middleware拦截传入的HTTP请求,并将最后的结果使 ...

  6. asp.net core如何自定义端口/修改默认端口

    .net core运行的默认端口是5000,但是很多时候我们需要自定义端口.有两种方式 写在Program的Main方法里面 添加 .UseUrls() var host = new WebHostB ...

  7. ASP.NET Core中自定义路由约束

    路由约束 ASP.NET Core中,通过定义路由模板,可以在Url上传递变量,同时可以针对变量提供默认值.可选和约束. 约束的使用方法是在属性路由上添加指定的约束名,用法如下: // 单个使用 [R ...

  8. asp.net core razor自定义taghelper

    又一个新的名词(taghelper),这个名词在netcore razor中也替代了(Htmlhelper),通过taghelper是可以操作html标签.条件输出.更是自由添加内外元素.当然也内置了 ...

  9. ASP.NET Core 中间件自定义全局异常处理

    目录 背景 ASP.NET Core过滤器(Filter) ASP.NET Core 中间件(Middleware) 自定义全局异常处理 .Net Core中使用ExceptionFilter .Ne ...

随机推荐

  1. JDBC基础篇(MYSQL)——PreparedStatement执行DML、DQL等

    注意:其中的JdbcUtil是我自定义的连接工具类:代码例子链接: package day03.prepare; import java.sql.Connection; import java.sql ...

  2. Web安全-CDN相关技术

    CDN介绍 CDN的全称是Content Delivery Network,即内容分发网络.CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡.内容分发. ...

  3. 前端云原生,以 Kubernetes 为基础设施的高可用 SSR(Vue.js) 渲染微服务初探(开源 Demo)

    背景 笔者在逛掘金的时候,有幸看到掘友狼族小狈开源的 genesis - 一个可以支持 SSR 和 CSR 渲染的微服务解决方案.总体来说思想不错,但是基于 Kubernetes 云原生部署方面一直没 ...

  4. vue组件里不用的css还在搜索过滤来删除?试一下vue-clearcss吧!

    这篇文章其实是推广介绍我个人的npm工具库,但你不会后悔点进来的(应该吧...)vue-clearcss 为什么要用它? 一个vue文件在长期迭代中css会越来越冗余,它不像html和js那么好删除, ...

  5. QT学习日记篇-03-仿写一个智能家居界面

    课程大纲: <1>让界面漂亮起来,仿写一个智能家居界面 ->第一:给QT工程添加图片 进入下一步: <注意路径和名称一定不能有中文>                   ...

  6. DNSPod DDNS 动态域名设置

    所谓动态域名,就是当你的服务器 IP 地址发生变化的时候,自动地修改你在「域名解析服务商」那里的域名记录值 怎么操作?看官方文档 DNSPod用户API文档 首先需要创建 Token 完整的 API ...

  7. 使用Keepalived实现Nginx的自动重启及双主热备高可用

    1.概述 之前我们使用Keepalived实现了Nginx服务的双机主备高可用,但是有几个问题没有解决,今天一起探讨一下. 1)在双机主备机制中,Keepalived服务如果宕了,会自动启用备机进行服 ...

  8. Identity基于角色的访问授权

    详情访问官方文档 例如,以下代码将访问权限限制为属于角色成员的用户的任何操作 AdministrationController Administrator : [Authorize(Roles = & ...

  9. squid缓存代理

    目录: 一.Squid 代理服务器 二.Squid 代理安装 三.搭建传统代理 四.搭建透明代理 五.ACL访问控制 六.Squid日志分析 七.反向代理 一.Squid 代理服务器Squid 主要提 ...

  10. IDEA SpotBugs代码安全审计插件

    IDEA SpotBugs代码安全审计插件 在寻找idea代码审计插件的时候,发现Findbugs已经停止更新,无法在idea2020.01版本运行,由此找到SpotBugs SpotBugs介绍 S ...