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

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

클라이언트 힌트는 사용자의 기기 및 연결된 네트워크에 관한 이러한 측면에 대한 통계를 제공하는 선택 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 이미지의 밀도 보정 내장 크기는 640x480을 2로 나눈 320x240입니다.

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

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

용어를 어느 정도 이해했으니 이제 사용할 수 있는 기기별 클라이언트 힌트 목록을 살펴보겠습니다.

표시 영역 너비

Viewport-Width는 CSS 픽셀 단위의 사용자 표시 영역 너비입니다.

Viewport-Width: 320

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

DPR

DPR(기기 픽셀 비율)은 사용자 화면의 실제 픽셀과 CSS 픽셀의 비율을 보고합니다.

DPR: 2

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

너비

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

예를 들어 사용자가 DPR이 2이고 CSS 픽셀 너비가 320인 화면이 있는 페이지를 요청한다고 가정해 보겠습니다. 기기는 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

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

네트워크 힌트

네트워크 정보 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 힌트를 확인하고 이미지 레이아웃 크기와 화면 밀도에 맞는 소스를 선택하여 이미지 해상도를 선택합니다 (xw 설명자가 srcset에서 작동하는 방식과 유사).
  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 헤더가 백엔드 코드에서 검사됩니다. 이 작업이 완료되면 더 나은 사용자 환경을 위해 개입해야 하는지 판단하는 데 사용할 수 있는 네트워크 품질 점수가 생성됩니다. 이 네트워크 점수는 0~1이며, 0는 최악의 네트워크 품질이고 1는 최상의 네트워크 품질입니다.

먼저 Save-Data가 있는지 확인합니다. 이 경우 사용자가 환경을 더 가볍고 빠르게 만들기 위해 필요한 모든 작업을 수행하기를 원한다고 가정하므로 점수가 0로 설정됩니다.

하지만 Save-Data이 없으면 다음 단계로 넘어가 ECT, RTT, Downlink 힌트의 값을 가중하여 네트워크 연결 품질을 설명하는 점수를 계산합니다. 네트워크 점수 생성 소스 코드는 GitHub에서 확인할 수 있습니다. 결론적으로, 일부 방식으로 네트워크 관련 힌트를 사용하면 느린 네트워크를 사용하는 사용자의 환경을 개선할 수 있습니다.

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

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

이 예에서는 느린 네트워크에서 사이트의 성능을 개선할 때 클라이언트 힌트가 미치는 영향을 확인할 수 있습니다. 아래는 클라이언트 힌트에 적응하지 않는 느린 네트워크의 사이트에 대한 WebPagetest 워터폴입니다.

느린 네트워크 연결에서 모든 리소스를 로드하는 Sconnie Timber 사이트의 WebPagetest 워터폴
그림 3. 느린 연결에서 이미지, 스크립트, 글꼴을 로드하는 리소스가 많은 사이트

이제 동일한 느린 연결에서 동일한 사이트의 워터폴을 살펴보겠습니다. 이번에는 사이트에서 클라이언트 힌트를 사용하여 중요하지 않은 페이지 리소스를 삭제합니다.

클라이언트 힌트를 사용하여 느린 네트워크 연결에서 중요하지 않은 리소스를 로드하지 않기로 결정하는 Sconnie Timber 사이트의 WebPagetest 폭포
그림 4. 동일한 연결의 동일한 사이트에서 더 빠른 로딩을 위해 '있으면 좋은' 리소스만 제외됩니다.

클라이언트 힌트를 사용한 결과 페이지 로드 시간이 45초 이상에서 1/10 미만으로 단축되었습니다. 이 시나리오에서 클라이언트 힌트의 이점은 아무리 강조해도 지나치지 않으며 느린 네트워크에서 중요한 정보를 찾는 사용자에게 큰 도움이 될 수 있습니다.

또한 클라이언트 힌트를 지원하지 않는 브라우저의 환경을 중단하지 않고 클라이언트 힌트를 사용할 수 있습니다. 예를 들어 지원되지 않는 브라우저에 전체 환경을 제공하면서 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`
`다운링크` `navigator.connection.downlink`
`Device-Memory` `navigator.deviceMemory`
파일 형식용 Imagemin 플러그인

이러한 API는 모든 곳에서 사용할 수 없으므로 in 연산자를 사용하여 기능 확인을 해야 합니다.

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

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

요약

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

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

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

리소스

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