반응형

HTTP range requests

HTTP 범위 요청이란 HTTP 를 통해 일정한 부분을 서버에서 클라이언트로 보내는 것을 Accept하고 보내는 방법입니다. 범위를 알 수 있는 대형 미디어 파일을 나누어서 읽을 수 있습니다. 파일 다운로드 도중 일시정지와 다시 시작 기능에 유용한 점을 이용해 클라이언트에선 미디어파일을 재생, 일시정지, 다시시작을 가능하게 만들 수 있습니다. 예를 들어 4.5mb짜리 파일을 받겠다하면, 서버는 전체 범위(Content-Length)와 일정 범위에 해당하는 파일을 bytes 로 내려보내줍니다.

참고

 

HTTP range requests

HTTP 범위 요청은 HTTP의 일정 부분만 서버에서 클라이언트로 보내도록 허락하는 것입니다. 부분 요청은 예를들어 대형 미디어나 파일 다운로드 도중 일시정지와 다시 시작 기능에 유용합니다.

developer.mozilla.org

 

HTML5 Video Tag

HTML5 <video> 는 HTTP range request를 사용하는 대표적인 태그입니다. 비슷하게는 <audio>도 존재합니다.
<video> 속성 태그로는 <source><track>를 사용할 수 있으며, <source>는 데이터의 유형을 나타내고 <track>은 재생 중 표시할 자막, 캡션 파일, 텍스트를 포함하는 파일을 표시할 수 있습니다.

참고

 

Spring Http Range Request 처리

Controller

@GetMapping("/videos/{name}")
    public ResponseEntity<ResourceRegion> getVideo(@PathVariable String name,
                                                   @RequestHeader HttpHeaders headers) throws IOException {

        log.info("getVideo");

        UrlResource video = new UrlResource("classpath:" + videoLocation + "/" + name);
        ResourceRegion region = resourceRegion(video, headers);
        return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
                            .contentType(MediaTypeFactory.getMediaType(video).orElse(MediaType.APPLICATION_OCTET_STREAM))
                            .body(region);
    }

MediaTypeFactory를 통해 파일의 content-type의 유형을 가져오거나, 기본값으로 8 bit 스트림 유형인 APPLICATION_OCTET_STREAM 리턴합니다.

잘 보시면 bodyResouceRegion 객체를 담아 보내는데요. ResourceRegion은 파일 객체의 Range 범위 만큼을 가져올 수 있는 스프링 코어 객체입니다.

ResourceRegion

private ResourceRegion resourceRegion(UrlResource video, HttpHeaders headers) throws IOException {

        final long chunkSize = 1000000L;
        long contentLength = video.contentLength();

        HttpRange httpRange = headers.getRange().stream().findFirst().get();
        if(httpRange != null) {
            long start = httpRange.getRangeStart(contentLength);
            long end = httpRange.getRangeEnd(contentLength);
            long rangeLength = Long.min(chunkSize, end - start + 1);
            return new ResourceRegion(video, start, rangeLength);
        } else {
            long rangeLength = Long.min(chunkSize, contentLength);
            return new ResourceRegion(video, 0, rangeLength);
        }
    }

처음 요청(else구문) 은 chunk 사이즈로 자른 시작값부터 청크 사이즈 만큼의 ResoureRegionreturn하고 그 다음 요청은 header에 담긴 range 범위만큼 짤라 보냅니다.

 

 

클라이언트 요청과 응답은 아래와 같습니다.

요청 된 범위요청의 Request / Response

Request에서는 bytes=1557056 과 같이 범위 요청이 일어난 것을 볼 수 있습니다.

Response에서는 Content-Type 은 video/mp4로 리턴되고, 청크 싸이즈만큼 컨텐츠 사이즈가 정해진 것을 볼 수 있습니다. 

 

 

서버는 각 요청을 지속적으로 받기 때문에 각기 다른 쓰레드로 처리된 것을 확인할 수 있습니다.

각기 다른 쓰레드로 처리한 것을 볼 수 있다.

 

파일사이즈 만큼 클라이언트가 범위요청한 내역입니다. HTTP code 206 상태는 분활 스트리밍 상태에서 정상응답 코드입니다.

 

 

 

Github 주소

위 예제는 중요 파트만 잘라 놓았음으로 자세한 소스를 보고 싶으시다면 아래 링크를 참고하세요.

https://github.com/Derveljun/derveljun-video-streaming

 

Derveljun/derveljun-video-streaming

Contribute to Derveljun/derveljun-video-streaming development by creating an account on GitHub.

github.com

 

반응형

WRITTEN BY
데르벨준

,