URL-адреса в JavaScript
URL-адреса являются важной частью любого веб-приложения. Если ваше приложение отправляет запросы к API, важно создать правильные URL-адреса для этих запросов. URL API, поддерживаемый всеми современными браузерами, предоставляет способ анализа URL-адресов и манипулирования ими. Это обеспечивает легкий доступ к различным частям URL-адреса.
Понимание частей URL-адреса
Рассмотрим следующий URL-адрес:
https://example.com/api/search?query=foo&sort=asc#results
Этот URL-адрес состоит из следующих компонентов:
- Protocol:
https
- Host:
example.com
- Path name:
/api/search
- Query string:
?query=foo&sort=asc
- Hash:
#results
С помощью современного JavaScript мы можем анализировать URL-адреса и извлекать эти различные части по мере необходимости.
Синтаксический анализ URL-адресов
В старых браузерах, до появления URL API, одним из способов анализа URL-адресов разработчиками было использование элемента <a>. Этот элемент обеспечивает базовый анализ URL-адресов. Например, вот способ извлечения строки запроса из URL-адреса:
function getQueryString(url) {
const link = document.createElement('a');
link.href = url;
return url.search;
}
Однако такой подход имеет некоторые недостатки:
- Для него требуется среда DOM, а это значит, что он не будет работать в такой среде, как Node.js.
- Он также не имеет обработки ошибок — если атрибуту передается недействительный URL
href
, ошибка не выдается.
Вы также могли бы использовать регулярное выражение для разбора различных частей URL-адреса, но это утомительно и чревато ошибками.
Использовать URL API для синтаксического анализа URL-адресов очень просто. Просто передайте URL-адрес, который вы хотите проанализировать, в конструктор URL-адресов. Если строка URL-адреса верна, вы получите обратно объект URL со свойствами для различных частей URL-адреса:
const url = new URL('https://example.com/api/search?query=foobar');
console.log(url.host); // example.com
console.log(url.pathname); // /api/search
console.log(url.search); // ?query=foobar
Разбор строки запроса
Вы можете получить доступ к строке запроса URL-адреса двумя способами:
- Свойство
search
, представляющее собой строку, содержащую полную строку запроса (включая?
символ) - Имущество
searchParams
, являющеесяURLSearchParams
объектом
Если вас интересует значение определенного параметра в строке запроса, вы можете использовать его метод get, чтобы получить параметр по его имени:
const url = new URL('https://example.com/api/search?query=foobar&maxResults=10');
console.log(url.searchParams.get('query'); // foobar
console.log(url.searchParams.get('maxResults'); // 10
Если существует несколько параметров с одинаковым именем, вы можете использовать GetAll, чтобы получить массив, содержащий все значения для этого имени:
const url = new URL('https://example.com/api/search?tag=tag1&tag=tag2&tag=tag3');
console.log(url.searchParams.getAll('tag')); // ['tag1', 'tag2', 'tag3']
Построение строк запроса
Построение строки запроса вручную может быть сложной задачей, особенно если какие-либо параметры запроса содержат специальные символы, которые необходимо экранировать. Например, если параметр запроса должен содержать символ &, вам нужно будет закодировать его как %26. Чтобы охватить эти ситуации, вам необходимо использовать функцию encodeURIComponent:
let queryString = 'foo=bar';
queryString += '&baz=qux';
queryString += '&tag=' + encodeURIComponent('one&two');
console.log(queryString); // foo=bar&baz=qux&tag=one%26two
Вы можете более безопасно создать строку запроса, используя объект URLSearchParams:
const params = new URLSearchParams();
params.append('foo', 'bar');
params.append('baz', 'qux');
params.append('tag', 'one&two');
console.log(params.toString()); // foo=bar&baz=qux&tag=one%26two
Преимущества использования URLSearchParams включают в себя:
- Вам не нужно беспокоиться о
&
символах, разделяющих параметры. - Вам не нужно кодировать URI-значения параметров.
- Вам не нужно использовать конкатенацию строк
Перебор параметров запроса
Без объекта URLSearchParams перебирать параметры в строке запроса немного сложно. Вам нужно было бы разделить строки несколько раз - сначала на группы пар ключ/значение, а затем снова разделить ключ и значение:
function listQueryParams(queryString) {
queryString.split('&').forEach(param => {
const [key, value] = param.split('=');
console.log(`${key}: ${value}`);
});
}
Если параметры могут содержать закодированные символы, вам также потребуется их декодировать:
function listQueryParams(queryString) {
queryString.split('&').forEach(param => {
const [key, value] = param.split('=');
console.log(`${key}: ${decodeURIComponent(value)}`);
});
}
Вместо этого вы можете использовать метод URLSearchParams entries для перебора пар ключ/значение:
function listQueryParams(queryString) {
const params = new URLSearchParams(queryString);
params.entries().forEach(([key, value]) => console.log(`${key}: ${value}`));
}
Создание полного URL-адреса
Вот полный пример создания URL-адреса с базовым URL-адресом и некоторыми параметрами запроса:
const url = new URL('https://example.com/api/search');
url.searchParams.append('query', 'test');
url.searchParams.append('tag', 'tag1');
url.searchParams.append('tag', 'tag2');
// https://example.com/api/search?query=test&tag=tag1&tag=tag2
console.log(url.toString());
Проверка правильных URL-адресов
Вы можете попробовать использовать регулярное выражение для проверки URL-адреса, но, как известно, очень сложно создать регулярное выражение, которое полностью отражает действительную строку URL-адреса.
Вместо этого вы можете обратиться к API URL. Конструктор URL выдаст ошибку, если вы укажете недопустимый URL. Вы можете использовать это, чтобы проверить, является ли URL допустимым:
function isValidURL(url) {
try {
new URL(url);
return true;
} catch (error) {
return false;
}
}
С новыми браузерами это стало еще проще. Существует новый статический метод URL.canParse, который выполняет аналогичную проверку с помощью одной строки кода. Как и функция isValidURL, описанная выше, она принимает потенциальную строку URL и возвращает значение true или false в зависимости от допустимости строки URL.
Создание относительных URL-адресов
URL API обладает мощным механизмом разрешения относительных URL-адресов. Обычно аргумент конструктора URL выдает ошибку, если он не является полным и допустимым URL-адресом. Однако вы можете указать второй аргумент, который служит основой для построения относительного URL-адреса. Если вы используете подход с двумя аргументами, то первый аргумент не обязательно должен быть допустимым URL-адресом, но второй должен быть допустимым.
Давайте сначала рассмотрим простой случай:
new URL('/about', 'https://example.com').href;
Конструктор URL принимает базовый URL из https://example.com и добавляет относительный путь /about, в результате чего получается https://example.com/about.
А как насчет этого:
new URL('profile', 'https://example.com/users').href;
Вы могли бы ожидать, что это будет https://example.com/users/profile, но на самом деле получается https://example.com/profile. Это ведет себя точно так же, как относительная ссылка; она берет родительский сегмент пути, который является корнем example.com, а затем добавляет profile.
Давайте рассмотрим еще один пример использования относительного URL-адреса. Вы также можете использовать .. для возврата вверх по иерархии путей:
new URL('../profile', 'https://example.com/users/123').href;
В этом случае получается https://example.com/profile. Помните, что относительные URL-адреса начинаются с родительского сегмента пути. Тогда в этом есть .., который ведет вверх еще на один сегмент пути.
Если вы вызовете конструктор URL-адресов с относительным URL-адресом и укажете недопустимый или неполный URL-адрес для базового URL-адреса, вы получите сообщение об ошибке. Вы также получите сообщение об ошибке, если используете относительный URL-адрес без полного базового URL-адреса:
new URL('../profile', '/about'); // error!
new URL('../profile'); // error
Работа с окном.расположение объекта
Возможно, вы знакомы с window.объект location, который представляет URL текущей страницы. У этого объекта также есть такие свойства, как href и pathname, поэтому вы можете подумать, что это объект URL. Это другой объект, Location, у которого есть некоторые общие свойства с URL, но также отсутствуют некоторые (например, свойство searchParams).
Даже если это не объект URL, вы все равно можете использовать window.location для создания новых объектов URL. Вы можете передать window.перейдите к конструктору URL-адресов, чтобы создать новый полноценный URL-адрес с параметрами поиска и всем остальным на основе текущего URL-адреса, или вы даже можете использовать его в качестве базового URL-адреса при создании относительных URL-адресов:
new URL('/profile', window.location).href;
Сопоставление шаблонов в URL-адресе с помощью URLPattern
Использование URL-адреса упрощает получение пути по URL-адресу. Например, в URL-адресе https://example.com/api/users/123/profile имя пути /api/users/123/profile. Что, если мы захотим получить только идентификатор пользователя, 123, по этому URL-адресу?
Как мы уже обсуждали ранее, может быть сложно создать правильные регулярные выражения для проверки и извлечения частей URL-адреса.
Пока что он доступен не во всех браузерах, но вы можете использовать URLPattern API для сопоставления и извлечения частей URL-адреса в соответствии с указанными вами шаблонами. Это может быть особенно полезно для таких вещей, как маршрутизация на стороне клиента в одностраничном приложении (SPA).
Используя URL-адрес профиля пользователя в качестве примера, давайте создадим шаблон URL-адреса, чтобы получить идентификатор пользователя. Мы можем использовать начальный символ : для обозначения именованного заполнителя, который может быть использован позже для сопоставления с этой частью URL-адреса:
const pattern = new URLPattern('https://example.com/api/users/:userId/profile');
const matcher = pattern.exec('https://example.com/api/users/123/profile');
console.log(matcher.pathname.groups.userId); // 123
Когда вы вызываете exec по URLPattern, ему нужен действительный URL-адрес. Он возвращает объект сопоставления, содержащий свойства для каждой части URL-адреса (протокол, хост, путь и т.д.). Каждое из этих свойств также имеет свойство groups, которое сопоставляет имена-заполнители, такие как :userId, с их значениями в URL-адресе.
Если вас интересует соответствие только одной части URL-адреса, например имени пути, как мы это сделали здесь, вы также можете указать подстановочные знаки в шаблоне URL-адреса. Или же вместо строки URL-адреса вы можете передать объект, содержащий те части URL-адреса, которые вас интересуют в сопоставлении:
new URLPattern('https://*/api/users/:userId/profile');
new URLPattern({ pathname: '/api/users/:userId/profile' });
API URLPattern по-прежнему доступен не во всех браузерах. На момент написания статьи он еще не поддерживался в Firefox или Safari. Вы можете ознакомиться с последней информацией о поддержке браузера по адресу CanIUse.com.
Резюме
URL API - это универсальный интерфейс для создания, проверки и манипулирования URL-адресами в JavaScript. Он более безопасен и менее подвержен ошибкам в использовании, чем ручной синтаксический анализ или регулярные выражения. Используя объект URLSearchParams, вы можете создать строку запроса, не беспокоясь о конкатенации строк или кодировании специальных символов.