Подход к стандартизации общих вариантов использования сопоставления с образцом.
Фон
Маршрутизация является ключевой частью каждого веб-приложения. По своей сути маршрутизация включает в себя получение 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
поддерживает необычную функцию среди библиотек маршрутизации: сопоставление источников , включая подстановочные знаки в именах хостов. Большинство других библиотек маршрутизации имеют дело только с pathname и иногда с поисковой или хэш- частью 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
, а первая строка считается относительно этой базы.
Независимо от того, предоставлена ли одна строка или две, конструктор 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
поддерживает символы Юникода несколькими различными способами.
Именованные группы, такие как
:café
, могут содержать символы Юникода. Правила, используемые для действительных идентификаторов JavaScript, применяются к именованным группам.Текст внутри шаблона будет автоматически закодирован в соответствии с теми же правилами, которые используются для кодирования URL-адресов этого конкретного компонента. Символы Юникода в
pathname
будут закодированы в процентах , поэтому шаблонpathname
, например/café
автоматически нормализуется до/caf%C3%A9
. Символы Юникода вhostname
автоматически кодируются с использованием Punycode , а не процентного кодирования.Группы регулярных выражений должны содержать только символы ASCII. Синтаксис регулярных выражений затрудняет и делает небезопасным автоматическое кодирование символов Юникода в этих группах. Если вы хотите сопоставить символ Юникода в группе регулярных выражений, вам необходимо вручную закодировать его в процентах, например
(caf%C3%A9)
чтобы соответствоватьcafé
.
Помимо кодирования символов Юникода, URLPattern
также выполняет нормализацию URL-адресов. Например, /foo/./bar
в компоненте pathname
сворачивается в эквивалент /foo/bar
.
Если вы сомневаетесь в том, как был нормализован данный шаблон ввода, проверьте созданный экземпляр URLPattern
с помощью DevTools вашего браузера.
Собираем все это вместе
Демонстрация Glitch, представленная ниже, иллюстрирует основной вариант использования URLPattern
внутри fetch event handler
сервисного работника, сопоставляя определенные шаблоны с асинхронными функциями, которые могут генерировать ответ на сетевые запросы. Концепции этого примера могут быть применены и к другим сценариям маршрутизации, как на стороне сервера, так и на стороне клиента.
Отзывы и планы на будущее
Хотя базовые функции URLPattern
теперь доступны в Chrome и Edge, запланированы дополнения. Некоторые аспекты URLPattern
все еще разрабатываются , и существует ряд открытых вопросов относительно конкретного поведения, которые еще могут быть уточнены. Мы рекомендуем вам опробовать URLPattern
и оставить отзыв через выпуск GitHub .
Поддержка шаблонов
Библиотека path-to-regexp
предоставляет compile() function
, которая эффективно меняет поведение маршрутизации. compile()
принимает шаблон и значения для заполнителей токенов и возвращает строку для URL-пути с подставленными этими значениями.
Мы надеемся добавить это в URLPattern в будущем, но это выходит за рамки первоначальной версии.
Включение будущих функций веб-платформы
Предполагая, что URLPattern
станет неотъемлемой частью веб-платформы, другие функции, которые могут получить выгоду от маршрутизации или сопоставления шаблонов, могут быть построены поверх него в качестве примитива.
Продолжаются дискуссии об использовании URLPattern
для предлагаемых функций, таких как сопоставление шаблонов области Service Worker , PWA в качестве обработчиков файлов и спекулятивная предварительная выборка .
Благодарности
Полный список благодарностей см. в исходном объяснительном документе .