requestAutocomplete

Lấy tiền của tôi, chứ đừng lấy thời gian của tôi

Jake Archibald
Jake Archibald

Giới thiệu

Tôi thích web. Nhìn chung, tôi nghĩ đó là một ý tưởng khá hay. Do đó, tôi đã tham gia nhiều cuộc tranh luận về web so với ứng dụng gốc. Người đó sẽ nhanh chóng bắt đầu nói về sự dễ dàng của việc thanh toán thông qua các hệ thống gốc. Câu trả lời thường thấy của tôi là thả bom khói rồi chạy ra khỏi phòng và cười điên dại, vì đó không phải là cuộc tranh luận mà tôi có thể thắng. Tỷ lệ bỏ ngang giỏ hàng trên web dành cho thiết bị di động có thể lên tới 97%. Hãy tưởng tượng điều đó trong thế giới thực. Hãy tưởng tượng 97% người ở siêu thị, với một giỏ hàng đầy ắp những thứ họ muốn, lật giỏ hàng và bước ra ngoài. Một số người trong số đó chỉ định giá sản phẩm và không bao giờ có ý định mua, nhưng trải nghiệm mua hàng tồi tệ của người dùng trên web là một yếu tố đóng góp đáng kể. Chúng tôi đang đánh thuế sự tỉnh táo của người dùng. Hãy nghĩ đến một trải nghiệm thanh toán thú vị mà bạn đã có trên web, đặc biệt là trên thiết bị di động. Đó là một cửa hàng ứng dụng, phải không? Hoặc ít nhất là một hệ thống khép kín tương tự đã có thông tin thanh toán của bạn. Đây là vấn đề. Chương trình này yêu cầu các trang web cam kết với một nhà cung cấp dịch vụ thanh toán cụ thể mà người dùng phải có tài khoản và đã đăng nhập, hoặc cam kết với một nền tảng yêu cầu người dùng phải đăng nhập vào một nhà cung cấp dịch vụ thanh toán cụ thể, chẳng hạn như cửa hàng ứng dụng yêu cầu bạn chỉ lập trình cho nền tảng đó. Nếu bạn không làm một trong những việc này, người dùng sẽ phải nhấn vào màn hình hoặc bàn phím cho đến khi da ngón tay của họ bị mòn hoặc họ bỏ cuộc. Chúng ta cần khắc phục vấn đề đó.

requestAutocomplete

Trong thế giới của WebGL, WebRTC và các API web bắt đầu bằng "Web", requestAutocomplete khá mờ nhạt. Tuy nhiên, đó là một siêu anh hùng mặc quần áo màu be. Một API nhỏ, nhàm chán có thể đâm xuyên tim của ma cà rồng thời gian thanh toán trên web.

Thay vì dựa vào một nhà cung cấp dịch vụ thanh toán cụ thể, trang web sẽ yêu cầu thông tin thanh toán từ trình duyệt. Trình duyệt sẽ thay mặt người dùng lưu trữ thông tin đó. Phiên bản requestAutocomplete() của Chrome cũng tích hợp với Google Wallet cho chỉ người dùng ở Hoa Kỳ (hiện tại). Thử nghiệm trên trang web thử nghiệm của chúng tôi.

form.requestAutocomplete

Các phần tử biểu mẫu chứa một phương thức mới duy nhất là requestAutocomplete. Phương thức này yêu cầu trình duyệt điền vào biểu mẫu. Trình duyệt sẽ hiển thị một hộp thoại yêu cầu người dùng cấp quyền và cho phép người dùng chọn thông tin chi tiết mà họ muốn cung cấp. Bạn không thể gọi phương thức này bất cứ khi nào bạn muốn, mà cần phải gọi trong quá trình thực thi các sự kiện tương tác cụ thể như sự kiện di chuột lên/xuống, nhấp, nhấn phím và chạm. Đây là một hạn chế bảo mật có chủ ý.

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

// TODO: listen for autocomplete events on the form

Trước khi xem xét các sự kiện, chúng ta cần đảm bảo trình duyệt hiểu các trường trong biểu mẫu của bạn…

Yêu cầu về biểu mẫu

Trước đây, khi Internet chỉ có màu đen trắng, Internet Explorer 5 đã sử dụng một thuộc tính mới là autocomplete trên các phần tử nhập dữ liệu của biểu mẫu. Bạn có thể đặt chế độ này thành "tắt" để trình duyệt ngừng đưa ra đề xuất. API này đã được mở rộng để bạn có thể chỉ định nội dung dự kiến của trường mà không cần sửa đổi thuộc tính "tên". Đây là nội dung mà requestAutocomplete sử dụng để liên kết các trường biểu mẫu với dữ liệu người dùng.

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

Theo thông số kỹ thuật, requestAutocomplete không dành riêng cho thanh toán, nhưng cách triển khai hiện tại của Chrome lại là như vậy. Trong tương lai, các trình duyệt có thể xử lý các loại dữ liệu khác, hy vọng là những dữ liệu như thông tin đăng nhập và trình tạo mật khẩu, thông tin hộ chiếu và thậm chí là tải hình đại diện lên.

Hiện tại, trong Chrome, requestAutocomplete nhận dạng những nội dung sau:

Thanh toán

  • email
  • cc-name – tên trên thẻ
  • cc-number – số thẻ
  • cc-exp-month – tháng hết hạn của thẻ ở dạng hai chữ số
  • cc-exp-year – năm hết hạn của thẻ ở dạng bốn chữ số
  • cc-csc – Mã bảo mật thẻ gồm 3-4 chữ số
<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">

Các thuộc tính "tên" mà tôi đã sử dụng ở trên chỉ là ví dụ, không có yêu cầu nào về việc sử dụng các giá trị cụ thể. Nếu định sử dụng lại biểu mẫu này cho những người dùng không có requestAutocomplete (tức là trường hợp lý tưởng), bạn nên thêm nhãn, bố cục và tính năng xác thực HTML5 cơ bản.

Bạn cũng không bị giới hạn ở các phần tử đầu vào, bạn có thể sử dụng bất kỳ loại dữ liệu đầu vào nào của biểu mẫu. Ví dụ: bạn có thể sử dụng <select> cho các trường ngày hết hạn của thẻ.

Thông báo chi tiết trên bảng điều khiển.
Thông báo chi tiết trên bảng điều khiển

Địa chỉ

  • name – họ và tên. Việc lấy họ tên làm một trường sẽ tốt hơn nhiều so với việc lấy nhiều trường. Nhiều trường như tên và họ thể hiện sự thiên vị về phương Tây và có thể không phù hợp với các nền văn hoá khác. Ngoài ra, việc nhập vào một trường sẽ dễ dàng hơn

  • tel – số điện thoại đầy đủ bao gồm cả mã quốc gia, có thể được chia thành

    • tel-country-code – ví dụ: +44
    • tel-national – phần còn lại
  • street-address – địa chỉ đầy đủ với các thành phần được phân tách bằng dấu phẩy, có thể được chia thành

    • address-line1
    • address-line2 – có thể để trống
  • địa phương – thành phố/thị trấn

  • khu vực – Mã tiểu bang, hạt hoặc bang

  • postal-code – Mã bưu chính, mã bưu điện, mã ZIP

  • country

Bạn nên sử dụng các thuộc tính trên cùng với: - thanh toán - vận chuyển

<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">
…

Xin nhắc lại rằng các thuộc tính tên là ví dụ, bạn có thể sử dụng bất kỳ tên nào bạn muốn. Rõ ràng là không phải biểu mẫu nào cũng cần yêu cầu địa chỉ giao hàng, ví dụ: đừng hỏi tôi muốn giao phòng khách sạn ở đâu, vì vị trí hiện tại của phòng khách sạn thường là điểm bán hàng. Vậy là chúng ta đã có biểu mẫu và biết cách yêu cầu autocompletion. Nhưng…

Khi nào bạn nên gọi requestAutocomplete?

Tốt nhất là bạn nên hiển thị hộp thoại requestAutocomplete thay vì tải trang hiển thị biểu mẫu thanh toán. Nếu mọi thứ diễn ra suôn sẻ, người dùng sẽ không thấy biểu mẫu.

Quy trình thanh toán

Một mẫu phổ biến là có một trang giỏ hàng với nút "thanh toán" đưa bạn đến biểu mẫu thông tin thanh toán. Trong trường hợp này, bạn muốn tải biểu mẫu thanh toán trên trang giỏ hàng, nhưng ẩn biểu mẫu đó khỏi người dùng và gọi requestAutocomplete trên biểu mẫu đó khi người dùng nhấn vào nút "thanh toán". Hãy nhớ rằng bạn cần phân phát trang giỏ hàng qua SSL để tránh cảnh báo Skeletor. Để bắt đầu, chúng ta nên ẩn nút thanh toán để người dùng không thể nhấp vào nút đó cho đến khi chúng ta sẵn sàng, nhưng chúng ta chỉ muốn làm điều này cho những người dùng có JavaScript. Vì vậy, trong phần đầu trang:

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

Và trong CSS:

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

Chúng ta cần thêm biểu mẫu thanh toán vào trang giỏ hàng. Bạn có thể đặt phần này ở bất cứ đâu, CSS ở trên sẽ đảm bảo người dùng không nhìn thấy phần này.

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

Bây giờ, JavaScript của chúng ta có thể bắt đầu thiết lập mọi thứ:

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
}

Bạn sẽ gọi enhanceForm trên trang giỏ hàng, đôi khi sau biểu mẫu và nút thanh toán. Những trình duyệt hỗ trợ requestAutocomplete sẽ có trải nghiệm nhanh và mới mẻ, còn các trình duyệt khác sẽ quay lại biểu mẫu thanh toán thông thường. Để nhận điểm thưởng, bạn nên tải HTML biểu mẫu thông qua XHR trong enhanceForm. Điều này có nghĩa là bạn chỉ có thể tải biểu mẫu trong các trình duyệt hỗ trợ requestAutocomplete và bạn không cần nhớ thêm biểu mẫu vào từng trang mà bạn có thể gọi enhanceForm. Đây là cách hoạt động của trang web minh hoạ.

Bạn đã gọi requestAutocomplete, giờ thì sao?

Quá trình tự động hoàn thành là không đồng bộ, requestAutocomplete trả về ngay lập tức. Để tìm hiểu xem điều đó đã diễn ra như thế nào, chúng ta sẽ theo dõi một vài sự kiện mới:

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
  }
});

Nếu mọi thứ đều hoạt động, bạn có thể làm bất cứ điều gì bạn muốn với dữ liệu. Việc đơn giản nhất bạn có thể làm là gửi biểu mẫu. Sau đó, máy chủ có thể xác thực dữ liệu và đưa người dùng đến trang xác nhận bao gồm cả phí giao hàng. Nếu dữ liệu không hợp lệ, bạn có thể hiển thị biểu mẫu và làm nổi bật những trường mà người dùng cần sửa đổi. Ngoài ra, bạn chỉ cần gửi biểu mẫu và để quy trình xác thực phía máy chủ thông thường của bạn tiếp tục. Nếu người dùng huỷ quy trình, bạn không cần làm gì cả. Nếu tính năng này bị tắt, hãy chuyển người dùng đến biểu mẫu thông thường. Vì vậy, trong hầu hết các trường hợp, trình nghe của bạn sẽ có dạng như sau…

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/';
  }
});

Trình duyệt lưu trữ dữ liệu của tôi ở đâu?

Quy cách này không chỉ định vị trí lưu trữ dữ liệu, cho phép trình duyệt đổi mới. Nếu đã đăng nhập vào Chrome, bạn có thể lưu trữ thông tin chi tiết trong Google Wallet để truy cập thông tin đó trên các thiết bị khác mà bạn đã đăng nhập. Nếu bạn lưu trữ thông tin chi tiết trong Wallet, requestAutocomplete sẽ không xử lý số thẻ thực của bạn, giúp tăng cường bảo mật. Nếu bạn chưa đăng nhập vào Chrome hoặc chọn không sử dụng Google Wallet, thông tin chi tiết của bạn sẽ được lưu trữ trên máy trong trình duyệt để sử dụng lại (không bắt buộc). Đây là tình trạng hiện tại, nhưng trong tương lai, Chrome và các trình duyệt khác có thể sử dụng thêm các nhà cung cấp dịch vụ thanh toán.

Thanh toán dễ dàng

Thật kỳ cục khi người dùng phải nhập đi nhập lại thông tin thanh toán mỗi khi họ muốn mua hàng. Việc thanh toán sẽ dễ dàng hơn khi một trang web lưu trữ thông tin thanh toán của bạn. Tuy nhiên, tôi hơi lo lắng về việc có bao nhiêu trang web lưu trữ thông tin thẻ của tôi. Đây là vấn đề hoàn hảo để giải quyết bằng các tiêu chuẩn web. requestAutocomplete có thể mang đến tính năng thanh toán một lần nhấp cho toàn bộ web, mà không cần phải sử dụng dịch vụ hoặc nền tảng nhất định.

Vòng thưởng: Xử lý biểu mẫu nhiều trang

Bạn nên gọi requestAutocomplete một lần và thu thập tất cả dữ liệu cần thiết. Nếu bạn không thể sửa đổi máy chủ để nhận tất cả dữ liệu này cùng một lúc, thì không sao, hãy lấy dữ liệu từ biểu mẫu đã hoàn tất và gửi theo cách phù hợp nhất với bạn. Bạn có thể sử dụng hàm nhỏ gọn này để thu thập tất cả dữ liệu hiện được hỗ trợ dưới dạng một đối tượng đơn giản mà không cần tự tạo biểu mẫu. Sau khi có dữ liệu, bạn có thể chuyển đổi thành định dạng bất kỳ mà máy chủ của bạn cần và đăng dữ liệu đó theo nhiều bước.

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
    });
  });
});