쓰리래빗츠 드라이브를 개발하면서 얻은 소소한 지식 중 HTTP Range
헤더에 대해 정리했습니다.
처음에는 동영상 스트리밍에 대한 지식이 없어서 요청받은 파일 전체를 내려보냈습니다. 파일 크기가 작을 때는 상관없지만 크기가 큰 동영상을 이렇게 서비스할 수는 없습니다. 그럴 때 쓰는 것이 HTTP Range
헤더입니다. HTTP Range
헤더로 파일 전체가 아니라 조금씩 나눠서 보낼 수 있습니다.1
웹 브라우저가 보내는 HTTP Range 헤더 요청은 다음과 같습니다.
Range: bytes=100-200
바이트가 단위입니다. 앞 숫자 100은 시작 위치를 200은 끝 위치를 의미합니다. 이 요청은 100바이트에서 200바이트까지의 데이터를 보내달라는 요청입니다. 시작 위치와 끝 위치 데이터를 포함하기 때문에 내려보내는 데이터 크기는 101바이트입니다.
HTTP Range
헤더 요청에 끝 위치가 없을 수 있습니다. 이 때는 임의로 끝 위치를 정합니다. 끝 위치에 따라 내려보내는 데이터 크기가 달라집니다. 끝 위치를 크게 설정하면 동영상을 보는 사용자가 기다리는 버퍼링 시간이 길어질 수 있습니다.
Range: bytes=100-
응답할 때는 HTTP Content-Range
헤더를 내려보냅니다.
Content-Range: bytes=100-200/1024
100과 200은 앞에서 설명한 것과 같고 1024는 전체 크기를 의미합니다. 끝 위치가 파일 크기에서 1을 뺀 것2보다 클 수 없습니다. 만약 파일 크기가 180이라면 다음과 같이 응답해야 합니다.
Content-Range: bytes=100-179/180
다음은 간단한 예제 코드입니다.
String range = request.getHeader("Range"); int i = range.indexOf("="); int j = range.indexOf("-"); long start = Long.parseLong(range.substring(i + 1, j)); long end = 0; if (j < range.length() - 1) { end = Long.parseLong(range.substring(j + 1)); } File file = getFile(); if (end == 0) { end = file.length() - 1; 1 } if (end > file.length() - 1) { end = file.length() - 1; 2 } response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); 3 response.setContentType("video/mp4"); response.setHeader("Accept-Ranges", "bytes"); response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + file.length()); response.setContentLength((int) (end - start + 1)); 4 RandomAccessFile rf = new RandomAccessFile(file, "r"); rf.seek(start); byte[] buffer = new byte[1024]; int num = 0; ServletOutputStream out = response.getOutputStream(); while (start < end && (num = rf.read(buffer)) != -1) { out.write(buffer, 0, num); out.flush(); start += 1024; }
1끝 위치가 없을 때는 파일의 크기를 끝으로 설정합니다.
2끝 위치가 파일 크기에서 1을 뺀 것보다 클 수 없습니다.
3응답 코드는 206 Partial Content
입니다.
4시작과 끝 위치를 포함하기 때문에 내려보내는 데이터 크기는 end - start + 1
입니다.
HTTP Range
헤더로 게시판 페이지 나눔을 구현하기도 합니다. 자세한 사항은 HTTP/1.1의 Range 요청과 이를 활용한 Pagination을 참고합니다.
다음을 참고합니다.
- 동영상을 보다가 재생 시간을 10분이나 1시간 앞으로 바꾸는 것도
HTTP Range
헤더가 있어서 가능합니다. 동영상 파일에 재상 시간과 파일 바이트 위치 정보가 있는 것으로 짐작할 수 있습니다. - 1을 빼는 이유는 데이터 위치가 배열처럼 0에서 시작하기 때문입니다.