@drawoharaя ❤️ це! << натисніть мене 🐛 🫖 🧚
/mobile-detection-behind-a-cdn
опубліковано: 2014-07-23

У недавньому проєкті ми повинні були створити мобільну версію існуючого вебсайту. Існуючий вебсайт не був хорошим кандидатом для адаптивного дизайну, тому ми вирішили створити повністю нову версію сайту для мобільних пристроїв.

5547851770_3598506559_z.jpg
_(фото від Johan Larsson)

Спочатку ми розглядали можливість використання шаблону m.example.com, де сайти є повністю окремими доменами. Однак оскільки ми не керуємо інфраструктурою для цього сайту, ми хотіли обійтися методом, який потребував би якомога менше змін інфраструктури. Підтримка іншого домену на тих же серверах не є надто складною, але це ще одна задача, яку легко можна зіпсувати і яка не є необхідною у нашому випадку.

Я також випустив цю техніку для легкого використання у додатку на Rails через двигун Rails:

Вступ до CloudFront

Однією з великих переваг цього конкретного вебсайту є те, що він використовує CloudFront. CloudFront — це мережа постачання контенту (CDN), де статичні вебсторінки розміщені на 52 дата-центрах по всьому світу. Це дозволяє сторінці надсилатися в браузер якомога швидше, оскільки незалежно від того, де ви знаходитесь у світі, ви не будете далеко від одного з вузлів CloudFront, тому займе менше часу для доставки вебсайту на ваше пристрій. CloudFront є частиною пропозиції AWS від Amazon і, крім гарантії швидкості, гарантує час безперервної роботи. (На відміну від S3, де гарантується лише час безперервної роботи.)

Коли ви використовуєте CloudFront, ви повідомляєте йому, де знаходиться ваш вебсервер, щоб CloudFront міг отримати останню версію вебсторінок, які він обслуговує для вас. CloudFront також запитує ваш вебсервер про нові версії ваших вебсторінок кожні кілька хвилин або через будь-який конфігурований вами інтервал часу в панелі керування CloudFront. Зазвичай це близько 24 годин. Це дозволяє CloudFront зосередитися на доступності та швидкості, значно зменшуючи навантаження на ваш вебсервер. (Це також займає час для CloudFront, щоб взяти нову версію сторінки та оновити всі 52 дата-центри.)

Однак це викликає проблему відстеження стану. Наприклад, якщо ваш сайт повністю обслуговується CloudFront, як ви підтримуєте вхід користувачів на ваш сайт? Якщо я користувач на ім'я Боб і сторінка на /my/account каже "Привіт, Боб!", CloudFront вважатиме, що всі, хто запитує сторінку на /my/account, повинні бачити версію сторінки, яка каже "Привіт, Боб!". Користувачі (за винятком, можливо, людей на ім'я Боб…) будуть дуже плутаними. Не тільки це, але що, якщо користувач оновлює якесь значення в своєму обліковому записі та очікує, що ця зміна відображатиметься миттєво? CloudFront не отримує нову версію сторінки на кожен запит (це б трохи порушило б мету CloudFront), він чекає кожні кілька хвилин, щоб отримати нову версію. CloudFront розв'язав деякі з цих питань завдяки новим функціям, але вам потрібно бути обізнаним про ці наслідки при використанні CloudFront.

У нашому випадку сайт, над яким ми працюємо, не має поняття "користувачів", і ніхто не може увійти до системи. Однак ми все одно хочемо, щоб CloudFront показував різні версії сайту в залежності від пристрою, з якого ви запитуєте сайт (мобільний чи настільний).

CloudFront може виконувати виявлення пристрою для вас, а потім надсилати спеціальний заголовок до вашого вебсервера, щоб сказати "Надай мені версію сторінки для телефону", однак ми хотіли контролювати метод виявлення пристрою (відповідь на питання - чи це телефон чи настільний пристрій?) і хотіли можливості для кінцевих користувачів та розробників обирати пристрій, обраний для них. Наприклад, кінцеві користувачі на планшетах можуть просто захотіти побачити настільну версію, навіть якщо ми спочатку показуємо їм мобільну версію. Нашим розробникам також буде важко перемикати свої пристрої кожного разу, коли вони хочуть перемикатися між версіями під час побудови сайту.

Наше рішення

Ось метод, який ми придумали для того, щоб як настільна, так і мобільна версії сайту знаходилися на одному домені та обслуговувалися CloudFront. Одне обов'язкове зауваження полягає в тому, що CloudFront зазвичай відключає всі файли cookie для вашого домену, але ви можете налаштувати його для дозволу файлів cookie, які ви називаєте. У нашому випадку ми сказали CloudFront дозволити файл cookie під назвою 'device'. Також варто відзначити, що ми знаходимося в контексті додатку Rails 4, але цю архітектуру можна відтворити в будь-якому стеку. Основна думка тут полягає в тому, що клієнт повинен визначити, на якому пристрої знаходиться користувач, дозволити їм це змінити та тримати сервер в курсі типу пристрою, щоб сервер міг обслуговувати правильні сторінки (це здійснюється за допомогою файлів cookie).

На кожній сторінці ми повинні робити щось схоже на це (уривок з app/views/layout/application.html.erb)

<%= javascript_include_tag "mobile_detection" %>

<script>

  if (!window.location.href.match(/get_device|set_device/)){
    console.log('logging the window.location.href = ' + window.location.href);
    localStorage.setItem('referrer_href', window.location.href);
  }

  var device_cookie  = cookie.get('device'),
      cookiesEnabled = cookie.enabled();

  if (cookiesEnabled && device_cookie == undefined) {
    window.location = '/get_device.html'
  }

</script>

Вищевказаний код просто запам'ятовує, на яку сторінку ви потрапили (зазвичай це головна сторінка, але ми хочемо, щоб клієнт міг ділитися посиланнями та щоб це працювало і на мобільному пристрої), а потім перенаправляє вас на сторінку /get_device, щоб виявити ваш пристрій, якщо ми ще не зробили це. Зверніть увагу на використання localStorage, що означає, що це працюватиме лише в IE8+ і не працюватиме в Opera Mini.

Також зверніть увагу, що вищевказаний фрагмент розміщений у <head> макету, щоб його виконувалося якомога швидше та до того, як будуть запущені будь-які скрипти настільної версії. У цьому випадку настільна версія активно використовує JavaScript для завантаження великої кількості контенту, тому ми дійсно не хотіли, щоб все це відбувалося на телефоні, перш ніж сайт визначив, що користувач повинен бачити мобільну версію сайту.

На кожній мобільній сторінці ми повинні робити це (з `app/views/layout/application.mobile.erb):

    <script>
      var device_cookie  = cookie.get('device'),
          cookiesEnabled = cookie.enabled();
 
      if (cookiesEnabled && device_cookie == 'desktop') {
        window.location.reload(true);
      }
    </script