记一个在制作服务器过程中遇到的坑

这是一篇关于HTTP 的响应头 Content-Range的记录文章

最近在做一个静态资源服务器【目前已完工,基本上可以处理静态资源】。在测试的时候发现一个Bug:Chrome下能正常解析的视频在Safari上无法解析。
视频代码大致如下,很简单:

<video src="movie.mp4" autoplay/>

Chrome的请求如下:
demo
在检查的时候发现红框内的这个特殊的请求头Range
与此同时,在Safari上发现能正常解析的视频文件的响应头内带有Content-Range这个Key。
demo2
于是开始漫长的查询与学习

分析响应

这种响应是在客户端表明自己需要请求服务端上的某种资源时产生的,通常发生在客户端持续请求一个未加载完成的资源的时候。
响应体内的Content-Range表示分段请求的请求数据的范围。

Content-Range: 0-65535/65536
0-65535 表示分段的数据范围
65536 表示数据总大小

而具有Content-Range头的响应,状态码也不是200 OK了,而是206 Partial Content

分析请求

知道响应的意思之后,反过来看请求头内的Range也就大概明白意思了

Range: bytes=0-1023
表示头1024个字节
Range: bytes=1024-2047
表示第二个1024字节
Range: bytes=0-
表示自第0字节开始之后的所有数据
Range: bytes=0-1024,-1
表示头1024个字节和最后一个字节

服务端需要返回的数据大小即由Range这个请求头来决定。
基于此,就需要对带有Range这个请求头的请求进行特殊的处理。

简单的处理

  1. 获取到起始字节start,终止字节end
  2. 从起始字节开始读文件,读到终止字节为止
  3. 将读完的文件返回
/**
 * 简单的处理Range: bytes=0-5和Range: byte=0-这两种情况
 * body 为读取到的数据
 */
FileInputStream fis = null;
try {
    String[] range = request.getHeaders().get("Range").split("=")[1].split("-");
    long start = Long.valueOf(range[0]);
    long end;
    try {
        end = Long.valueOf(range[1]);
    } catch (ArrayIndexOutOfBoundsException e) {
        // 如果出现该异常,则说明请求格式为Range: bytes=0-这样类型的情况
        end = file.length() - 1;
    }
    int size = (int) (end - start + 1);
    byte[] body = new byte[size];
    fis = new FileInputStream(file);
    fis.skip(start);
    fis.read(body);
    return body;
} catch(IOException e) {
    // do exception
} finally {
    // closeFis(fis);
}

还有一个注意的地方

Content-Length 这个头表示的是返回数据的大小,在第一次修改的时候忘记修改而导致Content-Length返回的是文件总大小,造成浏览器解析出错,这里需要提醒自己,多多注意细节。

之前以为了解的蛮多的HTTP协议、请求、响应这些东西,真正到自己去想办法造轮子的时候发现还是不够熟悉,了解的不够深入。这也给自己一个提醒,要勤造轮子,以巩固自己的学习。

****

Thanks for Reading

Jiahao.Zhang
NetEase Inc. Hangzhou 
        Front-End Developer