클라이언트 힌트를 사용하여 사용자에 맞게 조정

어디서나 빠른 사이트를 개발하는 것은 쉽지 않을 수 있습니다. 수많은 기기 기능과 기기가 연결되는 네트워크의 품질로 인해 이 작업이 불가능해 보일 수 있습니다. 브라우저 기능을 활용하여 로드 성능을 개선할 수 있지만 사용자 기기의 기능이나 네트워크 연결 품질을 어떻게 알 수 있을까요? 해결 방법은 클라이언트 힌트입니다.

클라이언트 힌트는 사용자 기기 및 연결된 네트워크의 이러한 측면에 대한 유용한 정보를 제공하는 선택적 HTTP 요청 헤더 집합입니다. 서버 측에서 이 정보를 활용하면 기기 또는 네트워크 상태에 따라 콘텐츠를 전송하는 방식을 변경할 수 있습니다. 이를 통해 더 포용적인 사용자 환경을 만들 수 있습니다.

콘텐츠 협상이 중요함

클라이언트 힌트는 콘텐츠 협상의 또 다른 방법으로, 브라우저 요청 헤더를 기반으로 콘텐츠 응답을 변경하는 것을 의미합니다.

콘텐츠 협상의 한 가지 예는 Accept 요청 헤더와 관련이 있습니다. 브라우저가 이해하는 콘텐츠 유형을 설명하며, 서버는 이를 사용하여 응답을 협상할 수 있습니다. 이미지 요청의 경우 Chrome의 Accept 헤더 콘텐츠는 다음과 같습니다.

Accept: image/webp,image/apng,image/*,*/*;q=0.8

모든 브라우저는 JPEG, PNG, GIF와 같은 이미지 형식을 지원하지만 이 경우 Accept는 브라우저가 WebPAPNG지원한다고 알려줍니다. 이 정보를 사용하여 각 브라우저에 가장 적합한 이미지 유형을 협상할 수 있습니다.

<?php
// Check Accept for an "image/webp" substring.
$webp = stristr($_SERVER["HTTP_ACCEPT"], "image/webp") !== false ? true : false;

// Set the image URL based on the browser's WebP support status.
$imageFile = $webp ? "whats-up.webp" : "whats-up.jpg";
?>
<img src="<?php echo($imageFile); ?>" alt="I'm an image!">

클라이언트 힌트는 Accept와 마찬가지로 콘텐츠를 협상하는 또 다른 방법이지만 기기 기능과 네트워크 상태의 맥락에서 이루어집니다. 클라이언트 힌트를 사용하면 네트워크 상태가 좋지 않은 사용자에게 중요하지 않은 리소스를 제공할지 여부 결정과 같이 사용자의 개별 환경을 기반으로 서버 측 성능 결정을 내릴 수 있습니다. 이 가이드에서는 사용 가능한 모든 힌트와 이를 사용하여 사용자에게 더 적합한 콘텐츠를 전송하는 방법을 설명합니다.

서비스 선택하기

Accept 헤더와 달리 클라이언트 힌트는 저절로 표시되지 않습니다 (나중에 설명할 Save-Data 제외). 요청 헤더를 최소로 유지하려면 사용자가 리소스를 요청할 때 Accept-CH 헤더를 전송하여 수신할 클라이언트 힌트를 선택해야 합니다.

Accept-CH: Viewport-Width, Downlink

Accept-CH의 값은 사이트에서 후속 리소스 요청의 결과를 결정하는 데 사용할 요청된 힌트의 쉼표로 구분된 목록입니다. 클라이언트가 이 헤더를 읽으면 '이 사이트에서 Viewport-WidthDownlink 클라이언트 힌트를 원합니다'라는 메시지가 표시됩니다. 특정 힌트 자체는 신경 쓰지 마세요. 잠시 후에 설명해 드리겠습니다.

이러한 선택 헤더는 모든 백엔드 언어로 설정할 수 있습니다. 예를 들어 PHP의 header 함수를 사용할 수 있습니다. <meta> 태그에서 http-equiv 속성을 사용하여 이러한 선택 헤더를 설정할 수도 있습니다.

<meta http-equiv="Accept-CH" content="Viewport-Width, Downlink" />

모든 클라이언트 힌트

클라이언트 힌트는 사용자가 사용하는 기기와 사이트에 액세스하는 데 사용하는 네트워크 중 하나를 설명합니다. 사용 가능한 모든 힌트를 간략하게 살펴보겠습니다.

기기 힌트

일부 클라이언트 힌트는 사용자 기기의 특성(일반적으로 화면 특성)을 설명합니다. 이 중 일부는 특정 사용자의 화면에 최적화된 미디어 리소스를 선택하는 데 도움이 될 수 있지만, 반드시 미디어 중심인 것은 아닙니다.

목록을 살펴보기 전에 화면과 미디어 해상도를 설명하는 데 사용되는 몇 가지 주요 용어를 알아두면 도움이 됩니다.

기본 크기: 미디어 리소스의 실제 크기입니다. 예를 들어 Photoshop에서 이미지를 열면 이미지 크기 대화상자에 표시되는 크기가 기본 크기를 나타냅니다.

밀도 보정된 내부 크기: 픽셀 밀도가 보정된 후의 미디어 리소스의 크기입니다. 이미지의 기본 크기기기 픽셀 비율로 나눈 값입니다. 예를 들어 다음 마크업을 살펴보겠습니다.

<img
  src="whats-up-1x.png"
  srcset="whats-up-2x.png 2x, whats-up-1x.png 1x"
  alt="I'm that image you wanted."
/>

이 경우 1x 이미지의 고유 크기가 320x240이고 2x 이미지의 고유 크기가 640x480이라고 가정해 보겠습니다. 화면 기기 픽셀 비율이 2인 기기 (예: Retina 화면)에 설치된 클라이언트에서 이 마크업을 파싱하면 2x 이미지가 요청됩니다. 2x 이미지의 밀도 보정된 고유 크기는 320x240입니다. 640x480을 2로 나눈 값이 320x240이기 때문입니다.

외부 크기: CSS 및 기타 레이아웃 요소 (예: widthheight 속성)가 적용된 후 미디어 리소스의 크기입니다. 밀도가 보정된 내부 크기가 320x240인 이미지를 로드하는 <img> 요소가 있지만, 이 요소에는 각각 256px192px 값이 적용된 CSS widthheight 속성도 있다고 가정해 보겠습니다. 이 예에서 <img> 요소의 외부 크기는 256x192가 됩니다.

고유 크기와 외부 크기를 보여주는 그림 320x240픽셀 크기의 상자가 INTRINSIC SIZE 라벨과 함께 표시됩니다. 그 안에는 CSS가 적용된 HTML img 요소를 나타내는 256x192픽셀 크기의 작은 상자가 있습니다. 이 체크박스의 라벨은 EXTRINSIC SIZE입니다. 오른쪽에는 img 요소의 레이아웃을 수정하여 외부 크기가 내부 크기와 다르도록 하는 요소에 적용된 CSS가 포함된 상자가 있습니다.
그림 1. 내적 크기와 외적 크기를 보여주는 그림 이미지는 레이아웃 계수가 적용된 후에 외부 크기를 갖게 됩니다. 이 경우 width: 256px;height: 192px;의 CSS 규칙을 적용하면 내부 크기가 320x240인 이미지가 외부 크기가 256x192인 이미지로 변환됩니다.

용어를 알아봤으니 이제 사용 가능한 기기별 클라이언트 힌트 목록을 살펴보겠습니다.

Viewport-Width

Viewport-Width는 사용자의 뷰포트 너비(CSS 픽셀)입니다.

Viewport-Width: 320

이 힌트는 다른 화면별 힌트와 함께 사용하여 특정 화면 크기 (예: 아트 디렉션)에 최적화된 이미지의 다양한 처리(예: 자르기)를 제공하거나 현재 화면 너비에 불필요한 리소스를 생략할 수 있습니다.

DPR

기기 픽셀 비율의 약자인 DPR는 사용자 화면의 실제 픽셀과 CSS 픽셀의 비율을 보고합니다.

DPR: 2

이 힌트는 화면의 픽셀 밀도에 해당하는 이미지 소스를 선택할 때 유용합니다 (예: srcset 속성에서 x 설명자가 하는 것처럼).

너비

Width 힌트는 sizes 속성을 사용하여 <img> 또는 <source> 태그에서 실행된 이미지 리소스 요청에 표시됩니다. sizes는 브라우저에 리소스의 외부 크기를 알려줍니다. Width는 이 외부 크기를 사용하여 현재 레이아웃에 최적화된 내부 크기의 이미지를 요청합니다.

예를 들어 사용자가 DPR이 2인 320CSS픽셀 너비 화면이 있는 페이지를 요청한다고 가정해 보겠습니다. 기기는 sizes 속성 값이 85vw<img> 요소 (즉, 모든 화면 크기의 뷰포트 너비의 85% 입니다. Width 힌트가 선택된 경우 클라이언트는 <img>src 요청과 함께 이 Width 힌트를 서버로 전송합니다.

Width: 544

이 경우 클라이언트는 요청된 이미지의 최적 내적 너비가 뷰포트 너비(272픽셀)의 85% 에 화면의 DPR(2)를 곱한 값(544픽셀)이라고 서버에 암시합니다.

이 힌트는 화면의 밀도 보정 너비를 고려할 뿐만 아니라 이 중요한 정보를 레이아웃 내 이미지의 외부 크기와 조정하기 때문에 특히 강력합니다. 이렇게 하면 서버가 화면 레이아웃 모두에 최적화된 이미지 응답을 협상할 수 있습니다.

Content-DPR

화면에는 기기 픽셀 비율이 있다는 것을 이미 알고 있지만 리소스에도 자체 픽셀 비율이 있습니다. 가장 간단한 리소스 선택 사용 사례에서는 기기와 리소스의 픽셀 비율이 동일할 수 있습니다. 하지만! DPRWidth 헤더가 모두 적용되는 경우 리소스의 외부 크기로 인해 두 헤더가 다른 시나리오가 발생할 수 있습니다. 여기에서 Content-DPR 힌트가 사용됩니다.

다른 클라이언트 힌트와 달리 Content-DPR는 서버에서 사용하는 요청 헤더가 아니라 DPRWidth 힌트를 사용하여 리소스를 선택할 때마다 서버가 전송해야 하는 응답 헤더입니다. Content-DPR 값은 다음 방정식의 결과여야 합니다.

Content-DPR = [선택한 이미지 리소스 크기] / ([Width] / [DPR])

Content-DPR 요청 헤더가 전송되면 브라우저는 화면의 기기 픽셀 비율 및 레이아웃에 맞게 지정된 이미지의 크기를 조절하는 방법을 알 수 있습니다. 이 속성이 없으면 이미지가 제대로 크기 조절되지 않을 수 있습니다.

Device-Memory

기술적으로 기기 메모리 API의 일부인 Device-Memory는 현재 기기에 있는 대략적인 메모리 양을 GiB로 나타냅니다.

Device-Memory: 2

이 힌트의 사용 사례는 메모리가 제한된 기기의 브라우저로 전송되는 JavaScript의 양을 줄이는 것입니다. JavaScript는 브라우저에서 일반적으로 로드하는 콘텐츠 유형 중에서 가장 리소스 집약적이기 때문입니다. 또는 디코딩하는 데 메모리를 덜 사용하는 낮은 DPR 이미지를 전송할 수도 있습니다.

네트워크 힌트

Network Information API는 사용자의 네트워크 연결 성능을 설명하는 또 다른 클라이언트 힌트 카테고리를 제공합니다. 제 생각에 가장 유용한 힌트입니다. 이를 통해 느린 연결에서 클라이언트에 리소스를 전송하는 방식을 변경하여 사용자에게 맞는 환경을 제공할 수 있습니다.

RTT

RTT 힌트는 애플리케이션 계층에서 대략적인 왕복 시간(밀리초)을 제공합니다. RTT 힌트는 전송 레이어 RTT와 달리 서버 처리 시간을 포함합니다.

RTT: 125

이 힌트는 로드 성능에서 지연 시간이 중요한 역할을 하기 때문에 유용합니다. RTT 힌트를 사용하면 네트워크 응답성을 기반으로 결정을 내릴 수 있으므로 전체 환경의 전송 속도를 높일 수 있습니다 (예: 일부 요청 생략).

로드 성능에 지연 시간이 중요하지만 대역폭도 영향을 미칩니다. 초당 메가비트 (Mbps)로 표시되는 Downlink 힌트는 사용자 연결의 대략적인 다운스트림 속도를 나타냅니다.

Downlink: 2.5

RTT와 함께 사용하면 Downlink는 네트워크 연결 품질에 따라 사용자에게 콘텐츠를 전송하는 방식을 변경하는 데 유용할 수 있습니다.

ECT

ECT 힌트는 효과적인 연결 유형을 나타냅니다. 값은 열거된 연결 유형 목록 중 하나이며, 각 유형은 지정된 RTTDownlink 값 범위 내의 연결을 설명합니다.

이 헤더는 실제 연결 유형을 설명하지 않습니다. 예를 들어 게이트웨이가 기지국인지 Wi-Fi 액세스 포인트인지 보고하지 않습니다. 대신 현재 연결의 지연 시간과 대역폭을 분석하고 가장 유사한 네트워크 프로필을 결정합니다. 예를 들어 Wi-Fi를 통해 느린 네트워크에 연결하면 ECT유효 연결에 가장 근접한 값인 2g이 채워질 수 있습니다.

ECT: 2g

유효한 ECT 값은 4g, 3g, 2g, slow-2g입니다. 이 힌트는 연결 품질을 평가하기 위한 시작점으로 사용하고 이후 RTTDownlink 힌트를 사용하여 세부 조정할 수 있습니다.

Save-Data

Save-Data는 네트워크 상태를 설명하는 힌트가 아니라 페이지에서 데이터를 더 적게 전송해야 한다고 명시하는 사용자 환경설정입니다.

Save-Data로 수행하는 많은 작업이 다른 네트워크 힌트와 유사하므로 Save-Data를 네트워크 힌트로 분류하는 것이 좋습니다. 또한 지연 시간이 길거나 대역폭이 낮은 환경에서 사용자가 이 모드를 사용 설정할 가능성이 높습니다. 이 힌트는 표시되는 경우 항상 다음과 같이 표시됩니다.

Save-Data: on

Google에서는 Save-Data로 할 수 있는 작업에 대해 이야기했습니다. 성능에 미치는 영향은 상당할 수 있습니다. 이는 사용자가 더 적은 양의 이메일을 보내 달라고 요청하는 신호입니다. 이러한 신호를 수신 대기하고 이에 따라 조치를 취하면 사용자는 만족할 것입니다.

종합하기

클라이언트 힌트로 수행하는 작업은 개발자에 따라 다릅니다. 다양한 정보를 제공하므로 다양한 옵션을 사용할 수 있습니다. 아이디어를 얻으려면 중서부 농촌에 위치한 가상의 목재 회사인 Sconnie Timber에서 클라이언트 힌트를 사용하면 어떤 이점이 있는지 살펴보겠습니다. 원격 지역에서 흔히 그렇듯이 네트워크 연결이 불안정할 수 있습니다. 이때 클라이언트 힌트와 같은 기술이 사용자에게 큰 도움이 될 수 있습니다.

반응형 이미지

가장 간단한 반응형 이미지 사용 사례를 제외한 모든 사용 사례는 복잡해질 수 있습니다. 다양한 화면 크기와 다양한 형식에 대해 동일한 이미지의 여러 처리 변형이 있는 경우 어떻게 해야 하나요? 이 마크업은 매우 빠르게 매우 복잡해집니다. 쉽게 잘못 이해할 수 있으며 중요한 개념 (예: sizes)을 잊어버리거나 오해하기 쉽습니다.

<picture>srcset는 의심할 여지 없이 훌륭한 도구이지만 복잡한 사용 사례를 위해 개발하고 유지하는 데 시간이 걸릴 수 있습니다. 마크업 생성을 자동화할 수 있지만 <picture>srcset가 제공하는 기능이 자동화의 유연성을 유지하는 방식으로 자동화해야 할 만큼 복잡하기 때문에 자동화하기도 어렵습니다.

클라이언트 힌트를 사용하면 이를 간소화할 수 있습니다. 클라이언트 힌트로 이미지 응답을 협상하는 방법은 다음과 같습니다.

  1. 워크플로에 해당하는 경우 먼저 Viewport-Width 힌트를 선택하여 이미지 처리 (예: 아트 디렉션 이미지)를 선택합니다.
  2. Width 힌트와 DPR 힌트를 선택하고 이미지의 레이아웃 크기와 화면 밀도에 맞는 소스를 선택하여 이미지 해상도를 선택합니다 (srcset에서 xw 설명자가 작동하는 방식과 유사).
  3. 브라우저에서 지원하는 가장 최적의 파일 형식을 선택합니다 (Accept를 사용하면 대부분의 브라우저에서 이 작업을 할 수 있음).

가상의 목재 회사 고객의 경우 PHP에서 고객 힌트를 사용하는 순진한 반응형 이미지 선택 루틴을 개발했습니다. 즉, 모든 사용자에게 이 마크업을 전송하는 대신 다음을 전송했습니다.

<picture>
  <source
    srcset="
      company-photo-256w.webp   256w,
      company-photo-512w.webp   512w,
      company-photo-768w.webp   768w,
      company-photo-1024w.webp 1024w,
      company-photo-1280w.webp 1280w
    "
    type="image/webp"
  />
  <img
    srcset="
      company-photo-256w.jpg   256w,
      company-photo-512w.jpg   512w,
      company-photo-768w.jpg   768w,
      company-photo-1024w.jpg 1024w,
      company-photo-1280w.jpg 1280w
    "
    src="company-photo-256w.jpg"
    sizes="(min-width: 560px) 251px, 88.43vw"
    alt="The Sconnie Timber Staff!"
  />
</picture>

개별 브라우저 지원을 기반으로 다음과 같이 줄일 수 있었습니다.

<img
  src="/image/sizes:true/company-photo.jpg"
  sizes="(min-width: 560px) 251px, 88.43vw"
  alt="SAY CHEESY PICKLES."
/>

이 예에서 /image URL은 PHP 스크립트이며 그 뒤에 mod_rewrite로 재작성된 매개변수가 옵니다. 백엔드 스크립트가 주어진 조건에서 가장 적합한 이미지를 선택하는 데 도움이 되는 이미지 파일 이름과 추가 매개변수를 사용합니다.

'하지만 백엔드에서 <picture>srcset를 다시 구현하는 것뿐 아닌가요?'가 첫 번째 질문일 것 같습니다.

어떤 면에서는 그렇습니다. 하지만 중요한 구분점이 있습니다. 애플리케이션이 클라이언트 힌트를 사용하여 미디어 응답을 작성하면 대부분의 작업 (전부는 아님)을 훨씬 더 쉽게 자동화할 수 있습니다. 여기에는 대신 이 작업을 실행할 수 있는 서비스 (예: CDN)가 포함될 수 있습니다. 반면 HTML 솔루션의 경우 모든 사용 사례를 제공하기 위해 새 마크업을 작성해야 합니다. 물론 마크업 생성을 자동화할 있습니다. 하지만 디자인이나 요구사항이 변경되면 향후 자동화 전략을 다시 검토해야 할 가능성이 큽니다.

클라이언트 힌트를 사용하면 무손실 고해상도 이미지로 시작하여 화면과 레이아웃의 모든 조합에 최적화되도록 동적으로 크기를 조절할 수 있습니다. 브라우저에서 선택할 수 있는 이미지 후보의 고정된 목록을 열거해야 하는 srcset과 달리 이 접근 방식은 더 유연할 수 있습니다. srcset는 브라우저에 대략적인 변형 세트(예: 256w, 512w, 768w, 1024w)를 제공하도록 강제하지만 클라이언트 힌트 기반 솔루션은 대량의 마크업을 사용하지 않고도 모든 너비를 제공할 수 있습니다.

물론 이미지 선택 로직을 직접 작성할 필요는 없습니다. Cloudinary는 w_auto 매개변수를 사용할 때 클라이언트 힌트를 사용하여 이미지 응답을 생성합니다. 클라이언트 힌트를 지원하는 브라우저를 사용할 때 중간 사용자의 다운로드 바이트 수가 42% 감소한 것으로 확인되었습니다.

하지만 주의해야 합니다. Chrome 67의 데스크톱 버전 변경으로 인해 교차 출처 클라이언트 힌트에 대한 지원이 중단되었습니다. 다행히 이러한 제한사항은 Chrome의 모바일 버전에 영향을 미치지 않으며 기능 정책 작업이 완료되면 모든 플랫폼에서 완전히 해제됩니다.

느린 네트워크를 사용하는 사용자 지원

적응형 성능은 클라이언트 힌트에서 제공하는 정보, 특히 사용자의 네트워크 연결의 현재 상태에 관한 정보를 기반으로 리소스를 제공하는 방식을 조정할 수 있다는 개념입니다.

Sconnie Timber의 사이트의 경우 네트워크가 느릴 때 백엔드 코드에서 Save-Data, ECT, RTT, Downlink 헤더를 검사하여 부하를 줄이는 조치를 취합니다. 이 작업이 완료되면 더 나은 사용자 환경을 위해 개입해야 하는지 판단하는 데 사용할 수 있는 네트워크 품질 점수가 생성됩니다. 이 네트워크 점수는 01 사이이며, 여기서 0은 가능한 최악의 네트워크 품질이고 1은 가장 좋습니다.

먼저 Save-Data가 있는지 확인합니다. 이 경우 점수는 0로 설정됩니다. 사용자가 환경을 더 가볍고 빠르게 만드는 데 필요한 모든 조치를 취하기를 바란다고 가정하기 때문입니다.

그러나 Save-Data가 없으면 계속해서 ECT, RTT, Downlink 힌트의 값을 가중치로 적용하여 네트워크 연결 품질을 나타내는 점수를 계산합니다. 네트워크 점수 생성 소스 코드는 GitHub에서 확인할 수 있습니다. 중요한 점은 어떤 방식으로든 네트워크 관련 힌트를 사용하면 느린 네트워크를 사용하는 사용자에게 더 나은 환경을 제공할 수 있다는 것입니다.

느린 네트워크 연결에 맞게 조정하기 위해 클라이언트 힌트를 사용하지 않는 사이트 (왼쪽)와 이를 사용하는 동일한 사이트(오른쪽)를 비교한 모습입니다.
그림 2. 지역 비즈니스 사이트의 '정보' 페이지 기준 환경에는 웹 글꼴, 캐러셀 및 악셀레이션 동작을 구동하는 JavaScript, 콘텐츠 이미지가 포함됩니다. 이러한 요소는 네트워크 상태가 너무 느려 빠르게 로드할 수 없는 경우에 생략할 수 있습니다.

사이트가 클라이언트 힌트가 제공하는 정보에 맞게 조정되는 경우 '전부 또는 전혀' 접근 방식을 채택할 필요가 없습니다. 전송할 리소스를 지능적으로 결정할 수 있습니다. 네트워크 품질이 좋지 않을 때 로드 성능을 높이기 위해 특정 디스플레이에 대해 품질이 낮은 이미지를 전송하도록 반응형 이미지 선택 로직을 수정할 수 있습니다.

이 예에서는 느린 네트워크에서 사이트의 성능을 개선하는 데 클라이언트 힌트가 미치는 영향을 확인할 수 있습니다. 다음은 느린 네트워크에서 클라이언트 힌트에 적응하지 않는 사이트의 WebPagetest 폭포식 차트입니다.

느린 네트워크 연결에서 모든 리소스를 로드하는 Sconnie Timber 사이트의 WebPagetest 폭포식 차트
그림 3. 느린 연결에서 이미지, 스크립트, 글꼴을 로드하는 리소스 집약적인 사이트

이제 동일한 느린 연결에서 동일한 사이트의 폭포식 구조입니다. 단, 이번에는 사이트에서 클라이언트 힌트를 사용하여 중요하지 않은 페이지 리소스를 제거합니다.

느린 네트워크 연결에서 중요하지 않은 리소스를 로드하지 않도록 결정하기 위해 클라이언트 힌트를 사용하는 Sconnie Timber 사이트의 WebPagetest 폭포식 차트입니다.
그림 4. 동일한 연결의 동일한 사이트로, 로드 속도를 높이기 위해 '좋을 텐데' 리소스만 제외됩니다.

클라이언트 힌트를 사용하면 페이지 로드 시간이 45초 이상에서 10분의 1 미만으로 줄었습니다. 이 시나리오에서 클라이언트 힌트의 이점은 충분히 강조할 수 없으며 느린 네트워크를 통해 중요한 정보를 찾는 사용자에게 큰 도움이 될 수 있습니다.

또한 클라이언트 힌트를 지원하지 않는 브라우저의 환경을 손상시키지 않고 클라이언트 힌트를 사용할 수 있습니다. 예를 들어 지원되지 않는 브라우저에 전체 환경을 계속 제공하면서 ECT 힌트 값을 사용하여 리소스 전송을 조정하려면 다음과 같이 기본값으로 대체할 수 있습니다.

// Set the ECT value to "4g" by default.
$ect = isset($_SERVER["HTTP_ECT"]) ? $_SERVER["HTTP_ECT"] : "4g";

여기서 "4g"ECT 헤더가 설명하는 최고 품질의 네트워크 연결을 나타냅니다. $ect"4g"로 초기화하면 클라이언트 힌트를 지원하지 않는 브라우저는 영향을 받지 않습니다. 선택이 최고야!

캐시를 주의하세요.

HTTP 헤더를 기반으로 응답을 변경할 때마다 캐시가 향후 해당 리소스의 가져오기를 처리하는 방식을 알고 있어야 합니다. Vary 헤더는 캐시 항목을 제공된 요청 헤더의 값으로 키를 지정하므로 여기에서 없어서는 안 됩니다. 간단히 말해, 지정된 HTTP 요청 헤더를 기반으로 응답을 수정하는 경우 거의 항상 다음과 같이 Vary에 해당 헤더를 요청해야 합니다.

Vary: DPR, Width

하지만 여기에는 주의점이 있습니다. 자주 변경되는 헤더 (예: Cookie)에서 캐시 가능한 응답을 Vary하면 안 됩니다. 이러한 리소스는 사실상 캐시할 수 없게 되기 때문입니다. 이를 알고 있으면 RTT 또는 Downlink와 같은 클라이언트 힌트 헤더에서 Vary를 피하는 것이 좋습니다. 이러한 헤더는 자주 변경될 수 있는 연결 요소이기 때문입니다. 이러한 헤더의 응답을 수정하려면 ECT 헤더만 키를 지정하는 것이 좋습니다. 이렇게 하면 캐시 누락이 최소화됩니다.

물론 이는 애초에 응답을 캐시하는 경우에만 적용됩니다. 예를 들어 콘텐츠가 동적인 경우 HTML 애셋을 캐시하지 않습니다. 반복 방문 시 사용자 환경이 손상될 수 있기 때문입니다. 이러한 경우 필요에 따라 언제든지 대답을 수정할 수 있으며 Vary에 관해 걱정하지 마세요.

서비스 워커의 클라이언트 힌트

콘텐츠 협상은 더 이상 서버에만 국한되지 않습니다. 서비스 워커는 클라이언트와 서버 간의 프록시 역할을 하므로 JavaScript를 통해 리소스가 전송되는 방식을 제어할 수 있습니다. 여기에는 클라이언트 힌트도 포함됩니다. 서비스 워커 fetch 이벤트에서 event 객체의 request.headers.get 메서드를 사용하여 다음과 같이 리소스의 요청 헤더를 읽을 수 있습니다.

self.addEventListener('fetch', (event) => {
  let dpr = event.request.headers.get('DPR');
  let viewportWidth = event.request.headers.get('Viewport-Width');
  let width = event.request.headers.get('Width');

  event.respondWith(
    (async function () {
      // Do what you will with these hints!
    })(),
  );
});

선택한 모든 클라이언트 힌트 헤더는 이 방식으로 읽을 수 있습니다. 하지만 이 방법만으로 이 정보를 얻을 수 있는 것은 아닙니다. 네트워크별 힌트는 navigator 객체의 다음과 같은 상응하는 JavaScript 속성에서 읽을 수 있습니다.

클라이언트 힌트 JS 상응
`ECT` `navigator.connection.effectiveType`
`RTT` `navigator.connection.rtt`
`Save-Data` `navigator.connection.saveData`
`Downlink` `navigator.connection.downlink`
`Device-Memory` `navigator.deviceMemory`
파일 형식용 Imagemin 플러그인입니다.

이러한 API는 일부 지역에서만 사용할 수 있으므로 in 연산자를 사용하여 기능을 확인해야 합니다.

if ('connection' in navigator) {
  // Work with netinfo API properties in JavaScript!
}

이제 서버에서 사용하는 것과 유사한 로직을 사용할 수 있습니다. 단, 클라이언트 힌트로 콘텐츠를 협상하는 데 서버가 필요하지는 않습니다. 서비스 워크만이 사용자가 오프라인 상태일 때 콘텐츠를 제공하는 추가 기능 덕분에 환경을 더 빠르고 탄력적으로 만들 수 있습니다.

요약

클라이언트 힌트를 사용하면 완전히 프로그레시브한 방식으로 사용자에게 더 빠른 환경을 제공할 수 있습니다. 특히 복잡한 사용 사례의 경우 <picture>srcset를 사용하는 것보다 반응형 이미지를 더 쉽게 게재할 수 있도록 사용자의 기기 기능을 기반으로 미디어를 게재할 수 있습니다. 이를 통해 개발 측의 시간과 노력을 줄일 수 있을 뿐만 아니라 및 srcset보다 더 세부적으로 사용자 화면을 타겟팅하는 방식으로 리소스(특히 이미지)를 최적화할 수 있습니다.

더 중요한 점은 전송하는 내용과 전송 방법을 수정하여 불량한 네트워크 연결을 감지하고 사용자의 격차를 해소할 수 있다는 것입니다. 이렇게 하면 불안정한 네트워크의 사용자가 사이트에 더 쉽게 액세스할 수 있습니다. 서비스 워커와 함께 사용하면 오프라인에서 사용할 수 있는 매우 빠른 사이트를 만들 수 있습니다.

클라이언트 힌트는 Chrome 및 Chromium 기반 브라우저에서만 사용할 수 있지만 이를 지원하지 않는 브라우저에 부담을 주지 않는 방식으로 사용할 수 있습니다. 클라이언트 힌트를 사용하여 모든 사용자의 기기 기능과 연결되는 네트워크를 인식하는 진정으로 포용적이고 적응 가능한 환경을 만드는 것이 좋습니다. 다른 브라우저 공급업체에서도 이 기능의 가치를 보고 구현 의지를 보일 수 있기를 바랍니다.

리소스

이 도움말에 관한 귀중한 의견과 수정을 제공해 주신 Ilya Grigorik, Eric Portis, Jeff Posnick, Yoav Weiss, Estelle Weyl님께 감사드립니다.