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

부분 응답이 요청되면 서비스 워커가 해야 할 일을 알고 있어야 합니다.

일부 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도 올바르게 작동합니다.

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

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

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

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

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

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

이 게시물의 히어로 이미지는 Unsplash의 Natalie Rhea Riggs가 작성했습니다.