서비스 워커에서 범위 요청 처리

게시일: 2020년 10월 6일

일부 HTTP 요청에는 전체 리소스의 일부만 반환해야 함을 나타내는 Range: 헤더가 포함되어 있습니다. 일반적으로 오디오 또는 동영상 콘텐츠를 스트리밍하는 데 사용되며, 원격 파일 전체를 한 번에 요청하는 대신 미디어의 작은 청크를 필요에 따라 로드할 수 있습니다.

서비스 워커는 웹 앱과 네트워크 사이에 위치하는 JavaScript 코드로, 전송되는 네트워크 요청을 가로채고 이에 대한 응답을 생성할 수 있습니다.

이전에는 범위 요청과 서비스 워커가 제대로 작동하지 않았습니다. 서비스 워커에서 좋지 않은 결과를 방지하기 위해 특별한 단계를 거쳐야 했습니다. 다행히도 이러한 상황이 바뀌기 시작했습니다. 올바른 동작을 보이는 브라우저에서는 서비스 워커를 통과할 때 범위 요청이 '그냥 작동'합니다.

무엇이 문제인가요?

모든 수신 요청을 가져와 네트워크에 전달하는 다음 fetch 이벤트 리스너가 있는 서비스 워커를 생각해 보세요.

self.addEventListener('fetch', (event) => {
  // The Range: header will not pass through in
  // browsers that behave incorrectly.
  event.respondWith(fetch(event.request));
});

동작이 잘못된 브라우저에서는 event.requestRange: 헤더가 포함된 경우 해당 헤더가 자동으로 삭제됩니다. 원격 서버에서 수신한 요청에는 Range:이 전혀 포함되지 않습니다. 서버는 원래 요청에 Range: 헤더가 있는 경우에도 200 상태 코드와 함께 전체 응답 본문을 반환할 수 있으므로 기술적으로 아무것도 '중단'되지 않습니다. 하지만 브라우저의 관점에서 엄격하게 필요한 것보다 더 많은 데이터가 전송됩니다.

이 동작을 알고 있는 개발자는 Range: 헤더의 존재를 명시적으로 확인하고 헤더가 있는 경우 event.respondWith()를 호출하지 않음으로써 이 문제를 해결할 수 있습니다. 이렇게 하면 서비스 워커가 응답 생성 그림에서 효과적으로 삭제되고 범위 요청을 유지하는 방법을 아는 기본 브라우저 네트워킹 로직이 대신 사용됩니다.

self.addEventListener('fetch', (event) => {
  // Return without calling event.respondWith()
  // if this is a range request.
  if (event.request.headers.has('range')) {
    return;
  }

  event.respondWith(fetch(event.request));
});

하지만 대부분의 개발자는 이 작업을 해야 한다는 것을 알지 못했습니다. 또한 필요한지 명확하지 않았습니다. 궁극적으로 이 제한은 이 기능을 지원하는 기본 사양의 변경사항브라우저가 따라잡아야 했기 때문에 발생했습니다.

수정된 사항

올바르게 작동하는 브라우저는 event.requestfetch()에 전달될 때 Range: 헤더를 보존합니다. 즉, 초기 예의 서비스 워커 코드는 브라우저에서 설정된 경우 원격 서버가 Range: 헤더를 볼 수 있도록 허용합니다.

self.addEventListener('fetch', (event) => {
  // The Range: header will pass through in browsers
  // that behave correctly.
  event.respondWith(fetch(event.request));
});

이제 서버에서 범위 요청을 적절하게 처리하고 206 상태 코드가 포함된 부분 응답을 반환할 수 있습니다.

어떤 브라우저가 올바르게 작동하나요?

최신 버전의 Safari에는 올바른 기능이 있습니다. 버전 87부터 Chrome과 Edge도 올바르게 작동합니다.

2020년 10월 현재 Firefox에서 이 동작을 아직 수정하지 않았으므로 서비스 워커의 코드를 프로덕션에 배포할 때 이 동작을 고려해야 할 수 있습니다.

웹 플랫폼 테스트 대시보드의 '네트워크 요청에 범위 헤더 포함' 행을 확인하면 특정 브라우저에서 이 동작이 수정되었는지 여부를 가장 잘 확인할 수 있습니다.

캐시에서 범위 요청을 처리하는 것은 어떤가요?

서비스 워커는 요청을 네트워크로 전달하는 것보다 훨씬 더 많은 작업을 할 수 있습니다. 일반적인 사용 사례는 오디오 및 동영상 파일과 같은 리소스를 로컬 캐시에 추가하는 것입니다. 그러면 서비스 워커가 네트워크를 완전히 우회하여 해당 캐시의 요청을 처리할 수 있습니다.

Firefox를 비롯한 모든 브라우저는 fetch 핸들러 내에서 요청을 검사하고, Range: 헤더의 존재를 확인한 다음, 캐시에서 가져온 206 응답으로 요청을 로컬에서 처리하는 것을 지원합니다. Range: 헤더를 올바르게 파싱하고 캐시된 전체 응답의 적절한 세그먼트만 반환하는 서비스 워커 코드는 간단하지 않습니다.

다행히도 도움이 필요한 개발자는 일반적인 서비스 워커 사용 사례를 간소화하는 라이브러리 집합인 Workbox를 사용할 수 있습니다. workbox-range-request module는 캐시에서 직접 부분 응답을 제공하는 데 필요한 모든 로직을 구현합니다. 이 사용 사례의 전체 레시피는 Workbox 문서에서 확인할 수 있습니다.