В этом посте я расскажу о своем опыте реализации маршрутизации на стороне клиента. Я просто хотел указать, что это не против каких-либо фреймворков или библиотек, но, пожалуйста, посмотрите это или признайте это как недостающую часть информации для помощи нашему сообществу.

Опять же, это может быть не полное и точное решение, которое вы, возможно, ищете. Но ссылка на некоторые проблемы, с которыми вы можете столкнуться.

Итак, начнем

В эту эпоху современной веб-разработки наиболее востребованной функцией является маршрутизация на стороне клиента. Это позволяет нам создавать одностраничные приложения (SPA, как его обычно называют).

Эта функция не зависит от каких-либо фреймворков или библиотек, но эти фреймворки или библиотеки никогда не упускают возможности иметь собственную маршрутизацию на стороне клиента в своей экосистеме.

Независимо от какой-либо структуры, основа или логика, реализующая маршрутизацию на стороне клиента, остается неизменной.

Так что же такое маршрутизация на стороне клиента?

Это то же самое, что маршрутизация на стороне сервера, но в браузере. Эта возможность изменять или настраивать его содержимое при изменении URL-адреса, даже не запрашивая у сервера контент, который ему необходимо отобразить, и без обновления всей страницы.

Реализация маршрутизации на стороне клиента осуществляется двумя способами.

Маршрутизация на основе хэша

Маршрутизация на основе хеша реализуется на основе якорной части URL-адреса. Например, https://example.com/#/product/list отображает список продуктов на странице.

Сосредоточьтесь на #/product/list, так как эта часть URL-адреса никогда не отправляется на сервер. Это позволяет нам полностью работать на стороне клиента.

Использование этого простого подхода поможет вам реализовать маршрутизацию на стороне клиента в вашем приложении без каких-либо проблем, о которых я расскажу чуть позже.

Но они далеки от совершенства. Они приходят со странным беспокойством, что их URL-адреса не всегда очень красивы.

Например, если перед вами стоит задача внедрить маршрутизацию на основе хеша и прокрутку на основе привязки на вашей веб-странице (т. е. щелкнуть тег привязки или кнопку, и вы прокручиваетесь до раздела страницы), URL-адрес будет выглядеть примерно так: https://example.com/#/#pricing-section

Не хорошо, верно? Но это становится еще хуже. Вы можете добавить внешнюю ссылку к urlhttps://example.com/#/https://stackoverflow.com/questions/10190215/, и она по-прежнему будет отображать вашу веб-страницу.

Так был ли фикс для этого, да был через форму History API

маршрутизация pushState

Или, точнее, как его называют в веб-экосистеме, BrowerRouter.

С выходом HTML5 мы получили window.history.pushState(), этот метод работает в связке с событием window.onpopstate.

Итак, когда мы хотим изменить запись в истории или в основном маршрут. Мы вызываем window.history.pushState(), передавая состояние, заголовок (что не так важно и обычно игнорируется браузерами) и сам URL. Который затем запускает событие onpopstate, где мы можем получить объект состояния и, наконец, отобразить раздел, который должен был отобразиться.

Этот тип маршрутизации довольно популярен в экосистеме маршрутизации на стороне клиента и довольно прост в использовании (если развертывание приложения происходит напрямую), и большинство фреймворков и библиотек используют его в качестве механизма маршрутизации на стороне клиента.

Но они приходят с небольшим разочаровывающим недостатком !!!

Позвольте мне перестать болтать и показать вам, что я имею в виду, на реальном примере.

Я использую React и React Router DOM для объяснения. Но, пожалуйста, я ни в коем случае не говорю, что они неправильные, и я пытаюсь их исправить или что-то в этом роде. Я просто использовал их, потому что их приняло большое количество разработчиков и компаний.

Кроме того, благодаря выразительному способу представления кода в React, это позволяет мне объяснять его гораздо проще и охватить более широкую аудиторию.

Итак, поехали!!

Сначала я создал приложение для реагирования через create-react-app и добавил react-router-dom для маршрутизации на стороне клиента.

Создал два маршрута Дом и О нас,вот скриншоты для них.

Сейчас мне нравится много заниматься дизайном, поэтому я хотел бы обратить ваше внимание на URL-адреса на скриншоте и внимательно изучить их, потому что этот пост на самом деле вращается вокруг них. URL-адрес меняется, когда я нажимаю кнопку «о программе», что совершенно очевидно.

Итак, все выглядит хорошо и отлично работает, теперь давайте сгенерируем рабочий пакет и разместим его. Для этого примера я решил разместить его с помощью бэкэнда node.js, созданного с помощью экспресс-версии.

Достаточно простой статический сервер для размещения моего сайта. Вы можете выбрать любой язык сервера, но то, что я собираюсь объяснить, остается прежним.

Теперь мой внутренний сервер готов, все, что мне нужно сделать, это создать клиентское приложение, скопировать пакет в общую папку на сервере и запустить его.

Команды, которым я следовал, чтобы сделать это,

yarn build и скопировал содержимое папки сборки в server/public с помощью cp -R ui/build/ server/public/

Итак, давайте запустим мой сервер node index.js, который начинает прослушивать порт 5000, если ошибок нет.

Ура, все работает, и я могу перейти к маршруту «/ about», когда нажимаю кнопку «About».

Так что это было завершено, я был готов перейти к моему следующему проекту.

Но... мое волнение было недолгим, я обнаружил, что существует так много проблем, о которых я даже не подозревал.

Так что же это за проблемы?

Я показал своему коллеге, и все работало, как и ожидалось, пока он не показал мне эту ошибку.

Как он до этого дошел, спросите вы? Не такой уж необычный способ, просто повседневный сценарий, когда вы обновляете страницу или вручную вводите URL-адрес.

Хорошо, тогда почему это проблема. Это мой пакет маршрутизатора? Неа.

Причина в том, что ваш внутренний сервер, тогда как в нашем случае сервер узла не имеет определенного маршрута /about для ответа, поэтому он выдает нам вышеуказанную ошибку.

Это разочаровывающий недостаток, о котором я говорил в маршрутизации на основе pushState.

Бывает так, что когда вы используете маршрутизацию на стороне клиента на основе истории или push-состояния. Вам нужно написать дополнительный бит кода на сервере, чтобы реагировать на эти URL-адреса на стороне клиента, когда они обновляются или вводятся вручную.

Помните, что это не относится к маршрутизации на основе хэша, потому что хэш-часть URL-адреса вообще никогда не отправляется на сервер.

Это не ново, давно есть. Но больше всего меня бесит то, что эти фреймворки маршрутизации на стороне клиента не упоминают их в своих документах, насколько я читал, и вы обычно видите их в некоторых выпусках Github.

Итак, исправим.

Добавлен маршрут /about на сервер, чтобы он мог отвечать. Как только начальная страница загружается, react-router-dom заботится о навигации по соответствующему маршруту.

Да!!, он рендерит экраны, и мы снова в деле. Я согласен, что это несколько дополнительный код. Но вы должны сделать это, чтобы исправить это.

Но это не имеет ничего общего с сервером узла или проблемой React или React-Router-DOM. Вот как ведет себя History API.

То же самое будет, когда вы используете Vue, Angular, Ember или любой другой фреймворк, серверы Python или Apache Tomcat. Вам также необходимо определить всю маршрутизацию на стороне клиента на сервере.

Но наша проблема еще не закончилась, на самом деле она стала очень сложной. Сценарии, о которых я буду говорить, будут немного сложными, но я постараюсь объяснить их простым языком.

В типичном проекте будет выделенный сервер или виртуальные машины или серверное пространство с соответствующими сопоставлениями DNS для размещения веб-сайта.

Но в системе, над которой мы работаем, у нас есть группа серверов приложений, объединенных в кластер или сгруппированных вместе для размещения всех наших приложений с Edge Gateway для проксирования запросов к нашим экземплярам приложений для масштабирования и обнаружения служб.

Чтобы объяснить это простым способом, я создал для этого диаграмму.

Поскольку у нас есть сопоставления с каждым экземпляром приложения в нашей конфигурации прокси, когда пользователь вводит https://localhost:8080/app/one, запросы перенаправляются в настроенный экземпляр приложения.

Системы такого типа очень эффективны для размещения нескольких приложений, чтобы использовать все возможности сервера. Обычно вы находите этот тип настройки более точным в архитектуре микросервисов.

Возвращаясь к проблеме. С такой настройкой среды, как вы заставите ваше приложение работать ??

Чтобы объяснить это более практично, вместо слов я настроил небольшую среду, как показано выше, с помощью ngnix.

Если вы не знаете о ngnix, перейдите сюда https://www.nginx.com/

Для этого я настроил прокси-сервер nginx в качестве обратного прокси-сервера, прослушивающего 8080, чтобы проксировать все мои запросы по выделенному пути к моему серверу приложений, прослушивающему порт 5000.

По сути, это говорит о том, что когда я получаю запрос от https://localhost:8080/app/one/, мне нужно передать его https://127.0.0.1:5000. Итак, давайте попробуем проверить, работает ли наш сайт.

Как и ожидалось, он не смог отобразить мой сайт. Почему? Из-за наших привязок пути к ресурсам

В приложении create-реагировать привязки ресурсов по умолчанию являются абсолютными. И это тоже вкратце обсуждалось в одном из выпусков их проекта на гитхабе.



Поэтому их решение состояло в том, чтобы добавить конфигурацию «домашней страницы» в package.json, чтобы сделать ее относительной, как показано ниже.

Я добавил исправление, как уже упоминалось, давайте соберем его и перезапустим мой сервер приложений.

Сработало, да вроде.

Так что же происходит? В этом случае вы видите раздел заголовка приложения, часть приложения, которая не находится под влиянием какой-либо маршрутизации на стороне клиента.

Наконец мы подошли к моменту, когда нам нужно разобраться с механизмом маршрутизации на стороне клиента.

Чтобы вы четко поняли, что происходит, давайте нажмем кнопку «О нас», где мы ожидаем, что она покажет мне страницу «О нас», верно?

Вуаля, он перемещается. Но не так скоро, пожалуйста, обратите внимание на URL. Да, мы больше не находимся в пределах URL нашего подкаталога https://localhost:8080/app/one/

На этом этапе, когда вы или клиент обновите URL-адрес, они увидят только ошибку 404 или, в нашем случае, это будет ошибка ngnix. Потому что мы ничего не настроили по этому пути на нашем прокси-сервере ngnix.

Причина в том, что он ведет себя так, потому что наши маршруты на стороне клиента всегда настроены одинаково. Маршруты всегда настроены на работу с маршрутом по умолчанию «/».

Хм... Но не беспокойтесь, наша библиотека дала нам способ это исправить.

Что вам нужно сделать, так это узнать путь к подкаталогу и настроить его как базовый путь для всей маршрутизации на стороне клиента.

В случае React-Router-Dom нам дали возможность настроить его, передав basename в качестве реквизита для компонента <Route>, как это.

В нашем случае наш путь к подкаталогу /app/one/

Хорошо, теперь наше приложение исправлено ??

Да, конечно, это исправлено, и все работает очень хорошо.

Но я столкнулся с более серьезной проблемой: что, если basename, которые вы знали, будут путем к подкаталогу или базовый путь вам неизвестен, хуже того, они не будут предоставлены даже во время сборки.

В нашей системе у нас есть полностью автоматизированный рабочий процесс. Когда вы нажимаете/фиксируете свой код. Запускается наша система сборки CI, настраиваются экземпляры контейнеров, настраивается пограничный шлюз и, наконец, развертывается приложение. Наша команда устранила необходимость в специалисте по DevOps для ручного развертывания нашего кода.

Достаточно хорошая проблема, как бы вы это исправили ??

К сожалению, я это исправил. Почему неудачная часть ??

Потому что люди начали называть это хаком (по-нашему называя это джугадом), а я называю это решением. Если вы глубоко понимаете, что мы, как инженеры, на самом деле делаем, так это обеспечиваем решения проблем, с которыми мы сталкиваемся.

Как я исправил, все это в другом посте, обещаю, что это не займет много времени? Но если вам нужно решение прямо сейчас, пожалуйста, напишите мне в мой твиттер https://twitter.com/santhoshraju2

Не хотел делать свой пост длиннее, а сложность проблемы была огромной.

А пока большое спасибо за прочтение. Надеюсь, это действительно поможет всем разработчикам, столкнувшимся с похожей проблемой, и заполнить недостающие части документации в наших пакетах и ​​библиотеках. И, пожалуйста, поделитесь, я в принципе не хотел бы видеть, как какой-либо разработчик сталкивается с подобной проблемой и тратит драгоценное время на поиск решения, как это сделал я.

Люблю вас, ребята, ура