【问题标题】:Chrome fails to load video if transferred with status 206 Partial Content如果传输状态为 206 Partial Content,Chrome 无法加载视频
【发布时间】:2019-12-05 13:36:18
【问题描述】:

我正在制作一个简单的 Java com.sun.net.httpserver.HttpServer 来提供静态视频文件。如果我返回状态代码 206,部分内容,当我尝试通过浏览器访问它时,视频无法播放(状态代码为 200 的视频可以正常播放,但我希望能够搜索和循环播放视频),这是我的HttpHandler

final String path = StaticHandler.toPathSafe(httpExchange.getRequestURI().getPath());
System.out.println(path);
final File file = new File(path);

if (file.isFile())
{
    int code = 200;
    long position = 0L;
    long end = file.length();

    if (httpExchange.getRequestHeaders().containsKey("Range"))
    {
        try
        {
            long[] range = StaticHandler.parseRange(httpExchange.getRequestHeaders().get("Range").get(0));

            position = range[0];
            if (range[1] != -1)
                end = range[1];

            // the video loads fine when code = 200;
            code = 206;

            httpExchange.getResponseHeaders().set("Content-Range", "bytes " + position + "-" + end + "/" + file.length());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    httpExchange.getResponseHeaders().set("Accept-Range", "bytes");
    httpExchange.getResponseHeaders().set("Content-Type", "video/mp4");
    httpExchange.getResponseHeaders().set("Content-Length", String.valueOf(end - position));

    System.out.println("Response: " + position + ", " + end);

    httpExchange.sendResponseHeaders(code, 0L);

    final FileChannel fileChannel = new FileInputStream(file).getChannel();
    final WritableByteChannel responseChannel = Channels.newChannel(response.getOutputStream());
    fileChannel.transferTo(position, end - position, responseChannel);

    responseChannel.close();
    fileChannel.close();
}
else
{
    System.out.println("404");
    httpExchange.sendResponseHeaders(404, -1);
}

以上代码无法在 chrome 上加载,但在 Firefox 中运行良好,这是我在 Chrome 中获得的标题:

Response Headers:

Accept-range: bytes
Content-length: 31491166
Content-range: bytes 0-31491166/31491166
Content-type: video/mp4
Date: Sat, 27 Jul 2019 14:32:55 GMT
Transfer-encoding: chunked


Request Headers:

Accept: */*
Accept-Encoding: identity;q=1, *;q=0
Accept-Language: en-US,en;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Host: 192.168.56.1:5000
Pragma: no-cache
Range: bytes=0-
Referer: http://192.168.56.1:5000/30MB.mp4
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36

我是否遗漏了什么和/或我的代码有什么问题?

【问题讨论】:

    标签: java google-chrome video-streaming html5-video httpserver


    【解决方案1】:

    范围包括起点-终点。不是起始长度

    例如:

    Content-range: bytes 0-0/31491166

    返回 1 个字节(从零字节到零字节)

    您的代码不起作用,因为浏览器正在等待一个永远不会发送的字节。

    【讨论】:

    • 例如,如果我想要视频的第一兆字节,我会发送一个范围为bytes=0-1023的请求
    【解决方案2】:

    使用下面的代码 sn-p。它可以在所有浏览器 Safari、Firefox 和 Chrome 上运行和测试。

    protected byte[] prepareContent(final HttpHeaders headers, byte[] media,
            String range) throws IOException {
        
        long rangeStart = 0;
        long rangeEnd;
    
        long fileSize = media.length;
        String[] ranges = range.split("-");
        rangeStart = Long.parseLong(ranges[0].substring(6));
    
        if (ranges.length > 1) {
            rangeEnd = Long.parseLong(ranges[1]);
        } else {
            rangeEnd = fileSize - 1;
        }
        if (fileSize < rangeEnd) {
            rangeEnd = fileSize - 1;
        }
        
        String contentLength = String.valueOf((rangeEnd - rangeStart) + 1);
        
        headers.add("Content-Length", contentLength);
        headers.add("Content-Range", "bytes " + rangeStart + "-" + rangeEnd + "/" + fileSize);
        headers.add("Content-Type", "video/mp4");
        headers.add("Accept-Ranges","bytes");
        return readByteRange(media, rangeStart, rangeEnd);
    }
    
    private byte[] readByteRange(byte[] media, long start, long end) throws IOException {
        
        try (InputStream inputStream = new ByteArrayInputStream(media);
             ByteArrayOutputStream bufferedOutputStream = new ByteArrayOutputStream()) {
            
            int nRead;
            while ((nRead = inputStream.read(media, 0, media.length)) != -1) {
                bufferedOutputStream.write(media, 0, nRead);
            }
            bufferedOutputStream.flush();
            byte[] result = new byte[(int) (end - start) + 1];
            System.arraycopy(bufferedOutputStream.toByteArray(), (int) start, result, 0, result.length);
            return result;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-04-03
      • 2013-03-25
      • 2012-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-07
      相关资源
      最近更新 更多