Опубликовано: 22 июля 2021 г.
Маршрутизация — ключевой элемент любого веб-приложения. По сути, маршрутизация принимает URL-адрес, применяет к нему сопоставление с шаблоном или другую специфичную для приложения логику, а затем, как правило, отображает веб-контент на основе полученного результата. Маршрутизация может быть реализована несколькими способами:
- Серверный код, сопоставляющий пути к файлам на диске.
- Логика в одностраничном приложении, которая ожидает изменений текущего местоположения, а затем создает и отображает соответствующий фрагмент DOM.
Хотя единого общепринятого стандарта не существует, веб-разработчики склоняются к общему синтаксису для выражения шаблонов маршрутизации URL-адресов, который во многом схож с regular expressions , но с некоторыми специфическими для предметной области дополнениями, такими как токены для сопоставления сегментов пути. Популярные серверные фреймворки, такие как Express и Ruby on Rails, используют этот синтаксис (или нечто очень близкое к нему), а разработчики JavaScript могут использовать модули, такие как path-to-regexp или regexpparam чтобы добавить эту логику в свой собственный код.
URLPattern — это дополнение к веб-платформе, основанное на фундаменте, созданном этими фреймворками. Его цель — стандартизировать синтаксис шаблонов маршрутизации, включая поддержку подстановочных знаков, именованных групп токенов, групп регулярных выражений и модификаторов групп. Экземпляры URLPattern , созданные с использованием этого синтаксиса, могут выполнять распространенные задачи маршрутизации, такие как сопоставление с полными URL-адресами или pathname к URL-адресу, и возвращать информацию о совпадениях токенов и групп.
Еще одно преимущество предоставления возможности сопоставления URL-адресов непосредственно в веб-платформе заключается в том, что общий синтаксис может быть использован другими API , которым также необходимо сопоставлять URL-адреса.
Поддержка браузеров и полифилы
URLPattern включена по умолчанию в Chrome и Edge версии 95 и выше.
Библиотека urlpattern-polyfill предоставляет способ использования интерфейса URLPattern в браузерах или средах, таких как Node , которые не имеют встроенной поддержки. Если вы используете полифил, убедитесь, что вы используете определение функций, чтобы гарантировать, что он загружается только в том случае, если текущая среда не поддерживает этот интерфейс. В противном случае вы потеряете одно из ключевых преимуществ URLPattern : тот факт, что средам с поддержкой не нужно загружать и анализировать дополнительный код для его использования.
if (!(globalThis && 'URLPattern' in globalThis)) {
// URLPattern is not available, so the polyfill is needed.
}
Синтаксическая совместимость
Основной принцип работы URLPattern — избегать повторного изобретения. Если вы уже знакомы с синтаксисом маршрутизации, используемым в Express или Ruby on Rails, вам не нужно изучать ничего нового. Но, учитывая небольшие расхождения в синтаксисе популярных библиотек маршрутизации, необходимо было выбрать базовый синтаксис, и разработчики URLPattern решили использовать синтаксис шаблонов из path-to-regexp (хотя и не его API) в качестве отправной точки.
Это решение было принято после тщательных консультаций с нынешним сопровождающим проекта path-to-regexp .
Лучший способ ознакомиться с основными принципами поддерживаемого синтаксиса — обратиться к документации по path-to-regexp . Вы можете прочитать документацию, предназначенную для публикации на MDN, в её текущем местоположении на GitHub.
Дополнительные функции
Синтаксис URLPattern является расширенным набором функций, поддерживаемых path-to-regexp , поскольку URLPattern поддерживает редкую для библиотек маршрутизации функцию: сопоставление источников , включая подстановочные знаки в именах хостов. Большинство других библиотек маршрутизации работают только с путем к URL-адресу , а иногда и с частью поиска или хеша . Им никогда не приходится проверять часть URL-адреса, относящуюся к источнику, поскольку они используются только для маршрутизации внутри автономного веб-приложения.
Учет источников открывает возможности для дополнительных вариантов использования, например, маршрутизации запросов из разных источников внутри обработчика события fetch сервис-воркера . Если вы маршрутизируете только URL-адреса из одного источника, вы можете фактически игнорировать эту дополнительную функцию и использовать URLPattern как другие библиотеки.
Примеры
Построение узора
Для создания объекта URLPattern передайте его конструктору либо строки, либо объект, свойства которого содержат информацию о шаблоне, с которым нужно выполнить сопоставление.
Передача объекта обеспечивает наиболее явный контроль над тем, какой шаблон использовать для сопоставления каждого компонента URL. В самом многословном виде это может выглядеть так:
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
search: '*',
hash: '*',
});
Указание пустой строки для свойства будет соответствовать условию только в том случае, если соответствующая часть URL-адреса не задана. Символ подстановки * будет соответствовать любому значению для заданной части URL-адреса.
Конструктор предлагает несколько упрощений для более удобного использования. Полное отсутствие свойств search и hash , или любых других, эквивалентно установке для них символа подстановки '*' . Пример можно упростить до:
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
});
В качестве дополнительного упрощения, всю информацию об источнике можно указать в одном свойстве, baseURL , что приведет к следующему результату:
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
Все эти примеры предполагают, что в вашем случае требуется сопоставление источников. Если вас интересует сопоставление только по остальным частям URL-адреса, исключая источник (как это часто бывает в сценариях маршрутизации с одним источником), вы можете полностью опустить информацию об источнике и указать лишь комбинацию свойств pathname , search и hash . Как и прежде, опущенные свойства будут рассматриваться как заданные с помощью шаблона * .
const p = new URLPattern({pathname: '/foo/:image.jpg'});
В качестве альтернативы передаче объекта в конструктор можно указать одну или две строки. Если указана одна строка, она должна представлять собой полный шаблон URL, включая информацию о шаблоне, используемую для сопоставления с источником. Если указаны две строки, вторая строка используется в качестве baseURL , а первая строка считается относительной к этому базовому URL.
Независимо от того, предоставлена ли одна или две строки, конструктор URLPattern проанализирует полный шаблон URL, разбив его на компоненты URL, и сопоставит каждую часть большего шаблона с соответствующим компонентом. Это означает, что на практике каждый URLPattern , созданный со строками, представляется так же, как и эквивалентный URLPattern созданный с помощью объекта. Конструктор со строками — это просто сокращение для тех, кто предпочитает менее многословный интерфейс.
const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');
При использовании строк для создания URLPattern следует учитывать несколько нюансов.
Пропуск свойства при использовании объекта для построения URLPattern эквивалентен указанию символа подстановки * для этого свойства. При разборе полного строкового шаблона URL, если в одном из компонентов URL отсутствует значение, это рассматривается так, как если бы свойство компонента было установлено в значение '' , что будет соответствовать только в том случае, если этот компонент пуст.
При использовании строк необходимо явно указывать подстановочные символы, если вы хотите, чтобы они использовались в создаваемом URLPattern .
// p1 and p2 are equivalent.
const p1 = new URLPattern('/foo', location.origin);
const p2 = new URLPattern({
protocol: location.protocol,
hostname: location.hostname,
pathname: '/foo',
search: '',
hash: '',
});
// p3 and p4 are equivalent.
const p3 = new URLPattern('/foo?*#*', location.origin);
const p4 = new URLPattern({
protocol: location.protocol,
hostname: location.hostname,
pathname: '/foo',
});
Также следует помнить, что разбор строкового шаблона на его компоненты может быть неоднозначным. Существуют символы, такие как : `, которые встречаются в URL-адресах, но также имеют особое значение в синтаксисе сопоставления шаблонов. Чтобы избежать этой неоднозначности, конструктор URLPattern предполагает, что любой из этих специальных символов является частью шаблона, а не частью URL-адреса. Если вы хотите, чтобы неоднозначный символ интерпретировался как часть URL-адреса, обязательно экранируйте его \` character. For example, the literal URL about:blank` should be escaped as `'about\:blank'`, если он предоставлен в виде строки.
Используйте шаблон
После создания объекта URLPattern у вас есть два варианта его использования. Методы test() и exec() принимают одни и те же входные данные и используют один и тот же алгоритм для проверки совпадения, отличаясь только возвращаемым значением. test() возвращает true если найдено совпадение с заданными входными данными, и false в противном случае. exec() возвращает подробную информацию о совпадении вместе с группами захвата или null , если совпадения нет. Следующие примеры демонстрируют использование exec() , но вы можете заменить любой из них на test() если вам нужно только логическое возвращаемое значение.
Один из способов использования методов test() и exec() — передача строк. Аналогично тому, что поддерживает конструктор, если предоставлена одна строка, она должна представлять собой полный URL-адрес, включая источник. Если предоставлены две строки, вторая строка рассматривается как значение baseURL , а первая строка оценивается как относительная к этому базовому значению.
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
const result = p.exec('https://example.com/foo/cat.jpg');
// result will contain info about the successful match.
// const result = p.exec('/foo/cat.jpg', 'https://example.com')
// is equivalent, using the baseURL syntax.
const noMatchResult = p.exec('https://example.com/bar');
// noMatchResult will be null.
В качестве альтернативы вы можете передать объект того же типа, что и в конструкторе, со свойствами, которые устанавливают только те части URL-адреса, которые вас интересуют.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
const result = p.exec({pathname: '/foo/:image.jpg'});
// result will contain info about the successful match.
При использовании exec() для URLPattern , содержащего подстановочные знаки или токены, возвращаемое значение будет содержать информацию о соответствующих значениях во входном URL. Это избавит вас от необходимости самостоятельно извлекать эти значения.
const p = new URLPattern({
hostname: ':subdomain.example.com',
pathname: '/*/:image.jpg'
});
const result = p.exec('https://imagecdn1.example.com/foo/cat.jpg');
// result.hostname.groups.subdomain will be 'imagecdn1'
// result.pathname.groups[0] will be 'foo', corresponding to *
// result.pathname.groups.image will be 'cat'
Анонимные и именные группы
При передаче строки URL в функцию exec() вы получаете значение, указывающее, какие части соответствуют всем группам шаблона.
Возвращаемое значение имеет свойства, соответствующие компонентам URLPattern , например, pathname . Таким образом, если группа была определена как часть pathname в URLPattern , то совпадения можно найти в pathname.groups возвращаемого значения. Совпадения отображаются по-разному в зависимости от того, является ли соответствующий шаблон анонимной или именованной группой.
Для доступа к значениям анонимного шаблона можно использовать индексы массива. Если анонимных шаблонов несколько, индекс 0 представляет собой значение, соответствующее самому левому шаблону, а индексы 1 и далее используются для последующих шаблонов.
При использовании именованных групп в шаблоне, результаты поиска отображаются в виде свойств, имена которых соответствуют имени каждой группы.
Поддержка и нормализация Unicode
URLPattern поддерживает символы Unicode несколькими способами.
Именованные группы, например
:café, могут содержать символы Юникода. К именованным группам применяются правила, используемые для допустимых идентификаторов JavaScript .Текст внутри шаблона будет автоматически кодироваться в соответствии с теми же правилами, которые используются для кодирования URL-адресов данного компонента. Символы Unicode в
pathnameбудут кодироваться с помощью процентного кодирования , поэтому шаблонpathnameнапример,/caféавтоматически нормализуется до/caf%C3%A9. Символы Unicode вhostnameавтоматически кодируются с использованием Punycode , а не процентного кодирования.Группы регулярных выражений должны содержать только символы ASCII. Синтаксис регулярных выражений затрудняет и делает небезопасным автоматическое кодирование символов Unicode в этих группах. Если вы хотите сопоставить символ Unicode в группе регулярных выражений, вам необходимо вручную закодировать его с помощью процента, например
(caf%C3%A9)для сопоставления сcafé.
Помимо кодирования символов Unicode, URLPattern также выполняет нормализацию URL-адресов. Например, /foo/./bar в компоненте pathname преобразуется в эквивалентный /foo/bar .
Если вы сомневаетесь в том, как был нормализован заданный входной шаблон, проверьте созданный экземпляр URLPattern с помощью инструментов разработчика вашего браузера.
Соберите всё воедино
Демонстрация Glitch иллюстрирует ключевой вариант использования URLPattern в fetch event handler сервис-воркера, сопоставляя определенные шаблоны с асинхронными функциями, которые могут генерировать ответ на сетевые запросы. Концепции, представленные в этом примере, могут быть применены и к другим сценариям маршрутизации, как на стороне сервера, так и на стороне клиента.
Отзывы и планы на будущее
Хотя базовый функционал URLPattern уже реализован в Chrome и Edge, планируется его дальнейшее расширение. Некоторые аспекты URLPattern всё ещё находятся в разработке , и существует ряд открытых вопросов относительно конкретных функций, которые могут быть доработаны. Мы рекомендуем вам попробовать URLPattern и оставить свой отзыв через GitHub Issues .
Поддержка шаблонизации
Библиотека path-to-regexp предоставляет compile() function , которая фактически обращает вспять поведение маршрутизации. compile() принимает шаблон и значения для заполнителей токенов и возвращает строку с URL-путем, в который подставлены эти значения.
Мы надеемся добавить это в URLPattern в будущем, но это не входит в планы первоначального релиза.
Обеспечить поддержку будущих функций веб-платформы
Если URLPattern станет неотъемлемой частью веб-платформы, то другие функции, которые могли бы выиграть от маршрутизации или сопоставления с шаблонами, могут быть построены на его основе в качестве базового элемента.
В настоящее время ведутся дискуссии об использовании URLPattern для предлагаемых функций, таких как сопоставление шаблонов области действия сервис-воркера , использование PWA в качестве обработчиков файлов и спекулятивная предварительная загрузка .
Полный список благодарностей см. в оригинальном пояснительном документе .