动态内容提供端点作为音频源,跳过不工作或下载不工作

时间:2017-12-12 15:40:47

标签: c# asp.net html5 audio range

我拥有什么

我有一个页面,它根据唯一ID返回音乐文件。

e.g。

Source.aspx?id=15 // returns 01_myfile.mp3
Source.aspx?id=37 // returns 02_something.flac
Source.aspx?id=3 // returns 03_anotherone.ogg

我想在html5 <audio> tag中使用这些来源。我让它在某个时候工作,但我无法在文件中跳过。就在那时我发现了Range标题并试图实现这一点。

...
Response.Clear();
Response.ClearHeaders();
Response.ClearContent();
Response.StatusCode = (Int32) HttpStatusCode.PartialContent;
Response.AddHeader("Accept-Ranges", "bytes");
Response.AddHeader("Content-Disposition", $"inline; filename=\"{file.FullName}\"");
Response.AddHeader("Content-Length", fileLength.ToString()); // e.g. 100
Response.AddHeader("Content-Range", $"{rangeFrom}-{rangeTo - 1}/{fileLength}"); // e.g. 0-99/100
Response.ContentType = GetContentType(file); // e.g. "audio/mpeg"
String contentDuration = t.Duration?.ToString() ?? "360"; // duration of the audio file or some default guess
Response.AddHeader("X-Content-Duration", contentDuration);
Response.AddHeader("Content-Duration", contentDuration);
Response.TransmitFile(file.FullName, rangeFrom, rangeTo - rangeFrom); // transmit requested section
Response.End();

外观如何

请求(Chrome) Request on chrome browser

Request URL:...Source.aspx?id=17686
Request Method:GET
Status Code:206 Partial Content
Remote Address:[::1]:51000
Referrer Policy:no-referrer-when-downgrade
Response Headers
view source
Accept-Ranges:bytes
Cache-Control:private
Content-Disposition:inline; filename="Z:\music\...\mymusicfile.mp3"
Content-Duration:360
Content-Length:12683228
Content-Range:0-12683227/12683228
Content-Type:audio/mpeg
Date:Tue, 12 Dec 2017 15:33:23 GMT
Server:Microsoft-IIS/10.0
X-AspNet-Version:4.0.30319
X-Content-Duration:360
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?...?=
Request Headers
view source
Accept:*/*
Accept-Encoding:identity;q=1, *;q=0
Accept-Language:en-US,en;q=0.9
Connection:keep-alive
Cookie:.ASPXAUTH=...
Host:localhost:51000
Range:bytes=0-
Referer:...
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36
Query String Parameters
view source
view URL encoded
id:17686

它只是停用控件。 activated and deactivated controls

问题

因此。我错过了什么?为什么这个版本没有按预期提供文件?

下载也不起作用。 enter image description here

有什么想法吗?谢谢!

1 个答案:

答案 0 :(得分:0)

就像我在评论中看到的那样,我在Content-Range中错过了单位。通过修复此问题,在音频文件中跳过和搜索就像魅力一样。

内容范围单位

从......

更改Content-Range格式
0-99/100

...到......

bytes 0-99/100

注意bytes部分?这就是单位。

状态代码

使用正确的状态代码进行响应对于所有功能都能正常工作至关重要。

并不总是包含范围标题。根据此情况,您必须使用不同的HTTP状态代码进行响应。

  
      
  • 第一种情况:如果提供了格式错误的范围标题,请回复416 请求范围 - 不是 - 满意的 HTTP状态代码,没有内容范围等元数据标题,也没有附加文件

  •   
  • 第二种情况:如果未提供范围标题,请使用200 确定 HTTP状态代码进行回复, OP中列出的所有元数据头和附加的完整文件内容范围

  •   
  • 第三种情况:如果提供了 0-范围标题,也请回复200 确定 HTTP状态代码和附加的完整文件内容范围

  •   
  • 第4种情况:对于提供的任何其他范围标题,请使用206 部分内容 HTTP状态代码进行回复和请求的内容范围

  •   

动态内容提供端点的完整工作代码

private readonly Dictionary<String, String> _mimeTypes =
    new Dictionary<String, String> {{".mp3", "audio/mpeg"}, {".wav", "audio/vnd.wav"}}; // all audio mime types i am interessted in which do not follow the "audio/fileextension" format

private void DownloadFile(String path)
{
    FileInfo file = new FileInfo(path);

    Int64 fileLength = file.Length;
    Int64 rangeTo = fileLength;
    String rangeHeader = Request.Headers["range"];
    String[] parts;

    if (rangeHeader != null)
    {
        rangeHeader = rangeHeader.Replace(" ", "").ToLower().Trim().Replace("bytes=", ""); // comes with the format of "bytes=0-100"
        parts = rangeHeader.Split('-').Where(x => !String.IsNullOrWhiteSpace(x)).ToArray(); splits into "0" and "100"
    }
    else
    {
        parts = new[] {"0"}; // simulate 0- range, full file will be returned
    }

    // trying to parse range
    Int64 rangeFrom = 0;
    switch (parts.Length)
    {
        case 2:
        {
            // full range passed (e.g. "100-200")
            if (!Int64.TryParse(parts[1], out rangeTo))
            {
                // cannot parse input to int -> invalid
                SendResponseRangeNotSatisfiable();
                return;
            }

            goto case 1;
        }
        case 1:
            // only start provided (e.g. "0-")
            if (!Int64.TryParse(parts[0], out rangeFrom))
            {
                // cannot parse input to int -> invalid
                SendResponseRangeNotSatisfiable();
                return;
            }

            goto case 0;
        case 0:
        {
            // no range provided, take default value for full file (e.g. "0-..")
            Response.Clear();
            Response.ClearHeaders();
            Response.ClearContent();
            Response.StatusCode = rangeFrom == 0 && rangeTo == fileLength
                ? (Int32) HttpStatusCode.OK
                : (Int32) HttpStatusCode.PartialContent;
            Response.AddHeader("Accept-Ranges", "bytes");
            Response.AddHeader("Content-Disposition", $"inline; filename=\"{file.FullName}\"");
            Response.AddHeader("Content-Length", fileLength.ToString());
            Response.AddHeader("Content-Range", $"bytes {rangeFrom}-{rangeTo - 1}/{fileLength}");
            Response.ContentType = _mimeTypes.ContainsKey(file.Extension)
                ? _mimeTypes[file.Extension]
                : $"audio/{file.Extension.Substring(1)}";
            String contentDuration = TheLengthOfYourMusicFileInSeconds;
            Response.AddHeader("X-Content-Duration", contentDuration);
            Response.AddHeader("Content-Duration", contentDuration);
            Response.TransmitFile(file.FullName, rangeFrom, rangeTo - rangeFrom);
            Response.Flush();
            Response.End();
            break;
        }
        default:
            SendResponseRangeNotSatisfiable();
            return;
    }
}

private void SendResponseRangeNotSatisfiable()
{
    Response.Clear();
    Response.ClearHeaders();
    Response.ClearContent();
    Response.StatusCode = (Int32) HttpStatusCode.RequestedRangeNotSatisfiable;
    Response.Flush();
    Response.End();
}