asp.net-core-mvc – 如何考虑请求和响应范围标头流式传输视频或文件?
发布时间:2020-05-23 19:18:40 所属栏目:asp.Net 来源:互联网
导读:我现在正在使用FileStreamResult,它可以传输视频,但无法搜索它.它总是从头开始. 我正在使用ByteRangeStreamContent,但它似乎不再可用于dnxcore50. 那怎么办? 我是否需要手动解析请求范围标头并编写自定义FileResult来设置响应Content-Range和其余标头,并将缓
|
我现在正在使用FileStreamResult,它可以传输视频,但无法搜索它.它总是从头开始. 我正在使用ByteRangeStreamContent,但它似乎不再可用于dnxcore50. 那怎么办? 我是否需要手动解析请求范围标头并编写自定义FileResult来设置响应Content-Range和其余标头,并将缓冲区范围写入响应主体,或者是否已经实现了某些内容并且我错过了它? 解决方法这是一个VideoStreamResult的简单实现,我现在正在使用(多部分内容部分未经过测试):public class VideoStreamResult : FileStreamResult
{
// default buffer size as defined in BufferedStream type
private const int BufferSize = 0x1000;
private string MultipartBoundary = "<qwe123>";
public VideoStreamResult(Stream fileStream,string contentType)
: base(fileStream,contentType)
{
}
public VideoStreamResult(Stream fileStream,MediaTypeHeaderValue contentType)
: base(fileStream,contentType)
{
}
private bool IsMultipartRequest(RangeHeaderValue range)
{
return range != null && range.Ranges != null && range.Ranges.Count > 1;
}
private bool IsRangeRequest(RangeHeaderValue range)
{
return range != null && range.Ranges != null && range.Ranges.Count > 0;
}
protected async Task WriteVideoAsync(HttpResponse response)
{
var bufferingFeature = response.HttpContext.Features.Get<IHttpBufferingFeature>();
bufferingFeature?.DisableResponseBuffering();
var length = FileStream.Length;
var range = response.HttpContext.GetRanges(length);
if (IsMultipartRequest(range))
{
response.ContentType = $"multipart/byteranges; boundary={MultipartBoundary}";
}
else
{
response.ContentType = ContentType.ToString();
}
response.Headers.Add("Accept-Ranges","bytes");
if (IsRangeRequest(range))
{
response.StatusCode = (int)HttpStatusCode.PartialContent;
if (!IsMultipartRequest(range))
{
response.Headers.Add("Content-Range",$"bytes {range.Ranges.First().From}-{range.Ranges.First().To}/{length}");
}
foreach (var rangeValue in range.Ranges)
{
if (IsMultipartRequest(range)) // dunno if multipart works
{
await response.WriteAsync($"--{MultipartBoundary}");
await response.WriteAsync(Environment.NewLine);
await response.WriteAsync($"Content-type: {ContentType}");
await response.WriteAsync(Environment.NewLine);
await response.WriteAsync($"Content-Range: bytes {range.Ranges.First().From}-{range.Ranges.First().To}/{length}");
await response.WriteAsync(Environment.NewLine);
}
await WriteDataToResponseBody(rangeValue,response);
if (IsMultipartRequest(range))
{
await response.WriteAsync(Environment.NewLine);
}
}
if (IsMultipartRequest(range))
{
await response.WriteAsync($"--{MultipartBoundary}--");
await response.WriteAsync(Environment.NewLine);
}
}
else
{
await FileStream.CopyToAsync(response.Body);
}
}
private async Task WriteDataToResponseBody(RangeItemHeaderValue rangeValue,HttpResponse response)
{
var startIndex = rangeValue.From ?? 0;
var endIndex = rangeValue.To ?? 0;
byte[] buffer = new byte[BufferSize];
long totalToSend = endIndex - startIndex;
int count = 0;
long bytesRemaining = totalToSend + 1;
response.ContentLength = bytesRemaining;
FileStream.Seek(startIndex,SeekOrigin.Begin);
while (bytesRemaining > 0)
{
try
{
if (bytesRemaining <= buffer.Length)
count = FileStream.Read(buffer,(int)bytesRemaining);
else
count = FileStream.Read(buffer,buffer.Length);
if (count == 0)
return;
await response.Body.WriteAsync(buffer,count);
bytesRemaining -= count;
}
catch (IndexOutOfRangeException)
{
await response.Body.FlushAsync();
return;
}
finally
{
await response.Body.FlushAsync();
}
}
}
public override async Task ExecuteResultAsync(ActionContext context)
{
await WriteVideoAsync(context.HttpContext.Response);
}
}
并解析请求标头范围: public static RangeHeaderValue GetRanges(this HttpContext context,long contentSize)
{
RangeHeaderValue rangesResult = null;
string rangeHeader = context.Request.Headers["Range"];
if (!string.IsNullOrEmpty(rangeHeader))
{
// rangeHeader contains the value of the Range HTTP Header and can have values like:
// Range: bytes=0-1 * Get bytes 0 and 1,inclusive
// Range: bytes=0-500 * Get bytes 0 to 500 (the first 501 bytes),inclusive
// Range: bytes=400-1000 * Get bytes 500 to 1000 (501 bytes in total),inclusive
// Range: bytes=-200 * Get the last 200 bytes
// Range: bytes=500- * Get all bytes from byte 500 to the end
//
// Can also have multiple ranges delimited by commas,as in:
// Range: bytes=0-500,600-1000 * Get bytes 0-500 (the first 501 bytes),inclusive plus bytes 600-1000 (401 bytes) inclusive
// Remove "Ranges" and break up the ranges
string[] ranges = rangeHeader.Replace("bytes=",string.Empty).Split(",".ToCharArray());
rangesResult = new RangeHeaderValue();
for (int i = 0; i < ranges.Length; i++)
{
const int START = 0,END = 1;
long endByte,startByte;
long parsedValue;
string[] currentRange = ranges[i].Split("-".ToCharArray());
if (long.TryParse(currentRange[END],out parsedValue))
endByte = parsedValue;
else
endByte = contentSize - 1;
if (long.TryParse(currentRange[START],out parsedValue))
startByte = parsedValue;
else
{
// No beginning specified,get last n bytes of file
// We already parsed end,so subtract from total and
// make end the actual size of the file
startByte = contentSize - endByte;
endByte = contentSize - 1;
}
rangesResult.Ranges.Add(new RangeItemHeaderValue(startByte,endByte));
}
}
return rangesResult;
} (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
相关内容
- 实体框架 – 为什么没有[Authorize(Roles =“Admin”)]在具
- asp.net – 如何在没有文件扩展名的情况下制作ASPX网页?
- asp.net – URL重写 – web.config错误
- asp.net-mvc – Bootstrap模式表单在提交后不会关闭
- asp.net-mvc-4 – Kendo UI组合框复位值
- asp.net-mvc – 使用带有剃刀的html选择框
- asp.net-mvc – 在ASP.NET MVC应用程序中记录用户活动
- asp.net-mvc – 不要在JSON中序列化Entity Framework类引用
- 验证 – 如何强制MVC验证IValidatableObject
- asp.net – ResolveUrl / Url.Content在Classic Asp中等效
推荐文章
站长推荐
- asp.net-mvc-3 – 如何使用ModelMetadata单元测试
- asp.net – 跟踪间歇性“对象引用未设置为对象的
- asp.net-mvc – Web部署由于文件正在使用而失败
- ASP.NET 程序中删除文件夹导致session失效问题的
- asp.net-mvc-3 – ASP .Net MVC 3不引人注目的客
- asp.net-mvc – 如何将数据从AuthorizeAttribute
- 选择ASP.NET MVC菜单项
- asp.net-mvc – 数据注释真的是一个好主意验证吗
- asp.net-mvc – 在Asp.NET MVC中以dd/mm/yyyy格式
- asp.net-mvc – 在ASP.NET MVC 3中授权当前用户对
热点阅读
