requestAutocomplete

시간을 뺏기지 말고 돈만 가져가세요

Jake Archibald
Jake Archibald

소개

웹이 좋습니다. 전반적으로 좋은 생각이라고 생각합니다. 따라서 웹과 네이티브에 관한 논쟁에 자주 참여하게 됩니다. 상대방이 네이티브 시스템을 통한 간편한 결제에 관해 이야기하기 시작하는 데 오래 걸리지 않습니다. 이 논쟁은 내가 이길 수 없으므로 연기 폭탄을 떨어뜨리고 미친 듯이 웃으며 방에서 뛰쳐나가는 것이 일반적인 대답입니다. 모바일 웹의 장바구니 포기율은 97%에 이를 수 있습니다. 실제 상황을 상상해 보세요. 슈퍼마켓에서 원하는 물건을 카트에 가득 채운 고객 중 97% 가 카트의 물건을 제자리에 되돌려 놓고 나가는 모습을 상상해 보세요. 물론 일부 사용자는 가격만 확인하고 구매할 의도가 없지만 웹에서의 구매 환경이 매우 좋지 않아서 구매를 망설이는 경우도 많습니다. 사용자의 정신 건강에 악영향을 미치고 있습니다. 웹에서, 특히 모바일에서 즐거운 결제 경험을 한 적이 있을 겁니다. 앱 스토어인가요? 또는 이미 결제 정보가 있는 유사한 비공개 시스템을 사용합니다. 이는 문제가 됩니다. 사이트에서 사용자가 이미 계정을 보유하고 로그인해야 하는 특정 결제 제공업체에 커밋하거나 사용자가 특정 결제 제공업체에 로그인해야 하는 플랫폼(예: 개발자가 해당 플랫폼용으로만 코딩해야 하는 앱 스토어)에 커밋해야 합니다. 이러한 작업 중 하나를 하지 않으면 사용자는 손가락 피부가 모두 사라지거나 포기할 때까지 화면이나 키보드를 계속 탭해야 합니다. 문제를 해결해야 합니다.

requestAutocomplete

WebGL, WebRTC, 'Web'으로 시작하는 기타 멋진 웹 API의 세계에서 requestAutocomplete는 다소 매력적이지 않습니다. 하지만 베이지색 옷을 입은 슈퍼히어로입니다. 웹 결제 시간 뱀파이어의 심장을 꿰뚫을 수 있는 작고 지루한 API입니다.

사이트가 특정 결제 제공업체에 의존하지 않고, 브라우저에서 결제 세부정보를 요청하여 사용자를 대신하여 저장합니다. Chrome 버전의 requestAutocomplete()는 현재 미국 사용자만 해당하는 Google 월렛과도 통합됩니다. 테스트 사이트에서 사용해 보세요.

form.requestAutocomplete

양식 요소는 브라우저에 양식을 채우도록 요청하는 단일 새 메서드인 requestAutocomplete를 보유합니다. 브라우저에서 사용자에게 권한을 요청하고 사용자가 제공할 세부정보를 선택할 수 있는 대화상자를 표시합니다. 이 메서드는 원하는 때마다 호출할 수 없으며 마우스 업/다운, 클릭, 키, 터치 이벤트와 같은 특정 상호작용 이벤트가 실행되는 동안 호출해야 합니다. 이는 의도적인 보안 제한입니다.

button.addEventListener('click', function(event) {
  form.requestAutocomplete();
  event.preventDefault();
});

// TODO: listen for autocomplete events on the form

이벤트를 살펴보기 전에 브라우저가 양식 필드를 이해하는지 확인해야 합니다.

양식 요구사항

인터넷이 흑백이었던 시절, Internet Explorer 5는 양식 입력 요소에 새로운 속성 autocomplete를 채택했습니다. '사용 안함'으로 설정하면 브라우저에서 추천을 제공하지 않도록 할 수 있었습니다. 'name' 속성을 수정하지 않고도 필드의 예상 콘텐츠를 지정할 수 있도록 이 API가 확장되었습니다. requestAutocomplete는 이 API를 사용하여 양식 필드를 사용자 데이터에 연결합니다.

<input name="fullname" autocomplete="name">

사양으로서 requestAutocomplete는 결제 전용은 아니지만 Chrome의 현재 구현은 거의 그렇습니다. 향후 브라우저가 로그인 세부정보, 비밀번호 생성기, 여권 정보, 아바타 업로드와 같은 다른 종류의 데이터를 처리할 수 있기를 기대합니다.

현재 Chrome에서 requestAutocomplete는 다음을 인식합니다.

결제

  • 이메일
  • cc-name - 카드에 표시된 이름
  • cc-number - 카드 번호
  • cc-exp-month - 카드 만료 월(2자리)
  • cc-exp-year - 카드 만료 연도(4자리)
  • cc-csc - 3~4자리 카드 보안 코드
<input type="email" autocomplete="email" name="email">
<input type="text" autocomplete="cc-name" name="card-name">
<input type="text" autocomplete="cc-number" name="card-num">
<input type="text" autocomplete="cc-exp-month" name="card-exp-month">
<input type="text" autocomplete="cc-exp-year" name="card-exp-year">
<input type="text" autocomplete="cc-csc" name="card-csc">

위에 사용한 'name' 속성은 예시일 뿐이며 특정 값을 사용할 필요는 없습니다. requestAutocomplete가 없는 사용자에게 이 양식을 재사용하려는 경우(이상적인 방법) 라벨, 레이아웃, 기본 HTML5 유효성 검사를 추가하는 것이 좋습니다.

입력 요소로 제한되지 않으며 모든 양식 입력 유형을 사용할 수 있습니다. 예를 들어 카드 만료일 입력란에 <select>를 사용할 수 있습니다.

자세한 콘솔 메시지
세부적인 콘솔 메시지

주소

  • name - 전체 이름 성명을 여러 필드로 사용하는 것보다 단일 필드로 사용하는 것이 훨씬 좋습니다. 이름과 성 등 여러 필드는 서구 편향이 있으며 다른 문화에서는 적절하지 않을 수 있습니다. 또한 하나의 필드에 입력하는 것이 더 쉽습니다.

  • tel - 국가 코드가 포함된 전체 전화번호로, 다음과 같이 분류할 수도 있습니다.

    • tel-country-code - 예: +44
    • tel-national - 기타
  • street-address - 구성요소가 쉼표로 구분된 전체 주소로, 다음과 같이 세분화할 수 있습니다.

    • address-line1
    • address-line2 - 비워 둘 수 있음
  • 지역 - 시/군/구

  • 지역 - 주 코드, 카운티 또는 주

  • postal-code - 우편번호

  • 국가

위의 항목은 다음과 함께 사용해야 합니다. - 결제 - 배송

<input type="text" autocomplete="billing name" required name="billing-name">
<input type="tel" autocomplete="billing tel" required name="billling-tel">
<input type="text" autocomplete="billing address-line1" required name="billing-address1">
<input type="text" autocomplete="billing address-line2" required name="billing-address2">
<input type="text" autocomplete="billing locality" required name="billing-locality">
<input type="text" autocomplete="billing region" required name="billing-region">
<input type="text" autocomplete="billing postal-code" required name="billing-postal-code">
<select autocomplete="billing country" required name="billing-country">
  <option value="US">United States</option>
  …
</select>

<input type="text" autocomplete="shipping name" name="shipping-name">
…

이름 속성은 예시일 뿐 원하는 이름을 사용할 수 있습니다. 물론 모든 양식에서 배송지 주소를 요청해야 하는 것은 아닙니다.예를 들어 호텔 객실 배송지를 묻지 마세요. 호텔의 현재 위치가 판매 포인트인 경우가 많습니다. 좋습니다. 양식이 준비되었고 autocompletion를 요청하는 방법을 알게 되었습니다. 하지만…

requestAutocomplete는 언제 호출해야 하나요?

결제 양식을 표시하는 페이지를 로드하는 대신 requestAutocomplete 대화상자를 표시하는 것이 좋습니다. 모든 것이 잘 진행되면 사용자에게 양식이 표시되지 않습니다.

결제 흐름

일반적인 패턴은 결제 세부정보 양식으로 연결되는 '결제' 버튼이 있는 장바구니 페이지를 사용하는 것입니다. 이 경우 장바구니 페이지에 결제 양식을 로드하지만 사용자에게 표시하지 않고 사용자가 '결제' 버튼을 누르면 requestAutocomplete를 호출합니다. Skeletor 경고를 피하려면 SSL을 통해 장바구니 페이지를 제공해야 합니다. 먼저 준비가 될 때까지 사용자가 결제 버튼을 클릭할 수 없도록 결제 버튼을 숨겨야 합니다. 하지만 JavaScript를 사용하는 사용자에게만 이 작업을 실행하려고 합니다. 따라서 페이지의 헤드에서 다음을 실행합니다.

<script>document.documentElement.className += ' js';</script>

CSS에서 다음을 실행합니다.

.js #checkout-button,
#checkout-form.for-autocomplete {
  display: none;
}

장바구니 페이지에 결제 양식을 포함해야 합니다. 이 div는 어디서나 사용할 수 있으며 위의 CSS를 사용하면 사용자에게 표시되지 않습니다.

<form id="checkout-form" class="for-autocomplete" action="/checkout" method="post">
  …fields for payment, billing address &amp; shipping if relevant…
</form>

이제 JavaScript에서 모든 설정을 시작할 수 있습니다.

function enhanceForm() {
  var button = document.getElementById('checkout-button');
  var form = document.getElementById('checkout-form');

  // show the checkout button
  button.style.display = 'block';

  // exit early if there's no requestAutocomplete support
  if (!form.requestAutocomplete) {
    // be sure to show the checkout button so users can
    // access the basic payment form!
    return;
  }

  button.addEventListener('click', function(event) {
    form.requestAutocomplete();
    event.preventDefault();
  });

  // TODO: listen for autocomplete events on the form
}

결제 양식과 버튼 이후에 장바구니 페이지에서 enhanceForm를 호출합니다. requestAutocomplete를 지원하는 브라우저에서는 새로운 고급 빠른 환경을 이용할 수 있고, 다른 브라우저에서는 일반 결제 양식으로 대체됩니다. 보너스 포인트로 enhanceForm의 일부로 XHR을 통해 양식 HTML을 로드할 수 있습니다. 즉, requestAutocomplete를 지원하는 브라우저에서만 양식을 로드할 수 있으며 enhanceForm를 호출할 수 있는 각 페이지에 양식을 추가할 필요가 없습니다. 데모 사이트의 작동 방식은 다음과 같습니다.

requestAutocomplete를 호출했습니다. 이제 어떻게 해야 하나요?

자동 완성 프로세스는 비동기식이며 requestAutocomplete는 즉시 반환됩니다. 결과를 확인하기 위해 몇 가지 새로운 이벤트를 수신 대기합니다.

form.addEventListener('autocomplete', function() {
  // hurrah! You got all the data you needed
});

form.addEventListener('autocompleteerror', function(event) {
  if (event.reason == 'invalid') {
    // the form was populated, but it failed html5 validation
    // eg, the data didn't match one of your pattern attributes
  }
  else if (event.reason == 'cancel') {
    // the user aborted the process
  }
  else if (event.reason == 'disabled') {
    // the browser supports requestAutocomplete, but it's not
    // available at this time. Eg, it wasn't called from an
    // interaction event or the page is insecure
  }
});

모든 것이 제대로 작동하면 데이터로 원하는 작업을 할 수 있습니다. 가장 간단한 방법은 양식을 제출하는 것입니다. 그러면 서버에서 데이터를 검증하고 사용자에게 배송비를 포함한 확인 페이지를 제공할 수 있습니다. 데이터가 잘못된 경우 양식을 표시하고 사용자가 수정해야 하는 필드를 강조 표시할 수 있습니다. 또는 양식을 제출하고 일반 서버 측 유효성 검사를 실행하도록 할 수도 있습니다. 사용자가 프로세스를 취소한 경우에는 별도로 취해야 할 조치가 없습니다. 기능이 사용 중지된 경우 사용자를 일반 양식으로 안내합니다. 따라서 대부분의 경우 리스너는 다음과 같이 표시됩니다.

form.addEventListener('autocomplete', function() {
  form.submit();
});

form.addEventListener('autocompleteerror', function(event) {
  if (event.reason == 'invalid') {
    form.submit();
  }
  else if (event.reason != 'cancel') {
    window.location = '/checkout-page/';
  }
});

브라우저는 내 데이터를 어디에 저장하나요?

이 사양은 데이터가 저장되는 위치를 지정하지 않으므로 브라우저에서 혁신을 할 수 있습니다. Chrome에 로그인하면 Google 월렛에 세부정보를 저장하여 로그인한 다른 기기에서 액세스할 수 있는 옵션이 제공됩니다. 월렛에 세부정보를 저장하면 requestAutocomplete에서 실제 카드 번호를 처리하지 않으므로 보안이 강화됩니다. Chrome에 로그인하지 않았거나 Google 월렛을 사용하지 않는 경우 세부정보가 재사용을 위해 브라우저에 로컬로 저장될 수 있습니다. 현재는 이 상태이지만 향후 Chrome 및 기타 브라우저에서 추가 결제 제공업체를 채택할 수 있습니다.

간편한 결제

사용자가 구매할 때마다 결제 정보를 반복해서 입력해야 하는 것은 어처구니가 없습니다. 사이트에서 결제 세부정보를 저장하면 편리하지만, 내 카드 세부정보를 저장하는 사이트가 얼마나 많은지 약간 불안합니다. 이는 웹 표준이 해결하기에 적합한 문제입니다. requestAutocomplete를 사용하면 서비스 또는 플랫폼 종속 없이 웹 전체에 원클릭 결제를 제공할 수 있습니다.

보너스 라운드: 여러 페이지 양식 처리

requestAutocomplete를 한 번 호출하여 필요한 모든 데이터를 수집하는 것이 훨씬 좋습니다. 이러한 데이터를 모두 한 번에 수신하도록 서버를 수정할 수 없는 경우에도 괜찮습니다. 작성된 양식에서 데이터를 가져와 가장 적합한 방법으로 제출하세요. 이 유용한 작은 함수를 사용하면 양식을 직접 만들지 않고도 현재 지원되는 모든 데이터를 간단한 객체로 캡처할 수 있습니다. 데이터를 가져온 후 서버에 필요한 형식으로 변환하고 여러 단계로 게시할 수 있습니다.

checkoutButton.addEventListener('click', function() {
  requestUserData({
    billing: true,
    shipping: true
  }, function(response) {
    if (response.err == 'cancel') {
      // exit silently
      return;
    }
    if (response.err) {
      // fall back to normal form
      window.location.href = '/normal-checkout-form/';
      return;
    }

    // the rest is just made-up pseudo code as an example
    postToServer(data.shipping).then(function() {
      return postToServer(data.billing);
    }).then(function() {
      return postToServer(data.cc);
    }).catch(function() {
      // handle error
    });
  });
});