Вбудований клас URL надає зручний інтерфейс для створення та розбирання URL на частини.
Зазвичай, щоб зробити мережевий запит, достатньо передати лише рядок з адресою, передавати саме екземпляр класу URL
не має жодної потреби. Тому нас ніхто не зобов’язує використовувати клас URL
. Але іноді це може стати в нагоді.
Створення URL
Синтаксис для створення URL
об’єктів:
new URL(url, [base])
url
– повний URL чи, якщо задано другий параметр, тільки шлях (дивись далі),base
– необов’язковий параметр з “основою” відносно якої буде побудовано URL, якщо в першому параметрі передано тільки шлях.
Наприклад:
let url = new URL('https://javascript.info/profile/admin');
В обох випадках буде згенеровано однакові URL:
let url1 = new URL('https://javascript.info/profile/admin');
let url2 = new URL('/profile/admin', 'https://javascript.info');
alert(url1); // https://javascript.info/profile/admin
alert(url2); // https://javascript.info/profile/admin
Можна легко створити новий URL із шляху ґрунтуючись на URL, що вже існує:
let url = new URL('https://javascript.info/profile/admin');
let newUrl = new URL('tester', url);
alert(newUrl); // https://javascript.info/profile/tester
Об’єкт URL
дозволяє негайно отримати доступ до його складових, тому це зручний спосіб для розбору URL адреси:
let url = new URL('https://javascript.info/url');
alert(url.protocol); // https:
alert(url.host); // javascript.info
alert(url.pathname); // /url
Підказка зі складовими URL об’єкту:
href
повна URL-адреса, те ж саме, щоurl.toString()
protocol
протокол, закінчується символом двокрапки:
search
– рядок з параметрами, починається символом знаку запитання?
hash
починається символом решітки#
- також можуть бути присутні властивості
user
таpassword
, якщо використовується формат для HTTP аутентифікації:http://login:password@site.com
(не згадано вище, бо рідко використовується).
URL
об’єкт можна передати у методи, що використовуються для мережевих запитів замість рядкуfetch
чи XMLHttpRequest
можуть використовувати URL
об’єкти майже всюди, де можна передати рядок з URL
.
Зазвичай, URL
об’єкт можна передати в будь-який метод замість рядку, оскільки більшість методів перетворять об’єкт в рядок, що містить повну URL-адресу.
Параметри пошуку “?…”
Припустимо, нам потрібно створити URL-адресу з заданими параметрами пошуку, наприклад, https://google.com/search?query=JavaScript
.
Ми, звичайно, можемо передати їх в рядку з URL-адресою:
new URL('https://google.com/search?query=JavaScript')
…Але параметри повинні бути закодованими, якщо вони містять пробіли, не латинські символи тощо (більше про це нижче).
Отже, для цього URL
має властивість: url.searchParams
, об’єкт типу URLSearchParams.
Він надає зручні методи для роботи з параметрами пошуку:
append(name, value)
– додати параметр з іменемname
,delete(name)
– видалити параметр з іменемname
,get(name)
– отримати значення параметру з іменемname
,getAll(name)
– отримати всі параметри, що мають ім’яname
(наприклад,?user=John&user=Pete
),has(name)
– перевірити чи існує параметр з іменемname
,set(name, value)
– встановити/замінити параметр з іменемname
,sort()
– відсортувати параметри за іменем, рідко стає в нагоді,- …і це об’єкт також можна перебрати, подібно до
Map
.
Приклад з параметрами, що містять пробіли та знаки пунктуації:
let url = new URL('https://google.com/search');
url.searchParams.set('q', 'test me!'); // додано параметр з пробілом та !
alert(url); // https://google.com/search?q=test+me%21
url.searchParams.set('tbs', 'qdr:y'); // додано параметр з двокрапкою :
// параметри автоматично закодовано
alert(url); // https://google.com/search?q=test+me%21&tbs=qdr%3Ay
// у циклі перебираємо всі параметри пошуку (кожен параметр автоматично декодується)
for(let [name, value] of url.searchParams) {
alert(`${name}=${value}`); // q=test me!, then tbs=qdr:y
}
Кодування
Набір символів, що можуть дозволено до використання в URL-адресах, визначено в стандарті RFC3986.
Усі інші символи, що не дозволені стандартом, повинні бути закодовані. Наприклад, не латинські букви та пробіли мають бути замінені на їх UTF-8 коди, що починаються з %
. Пробіл буде закодовано у вигляді %20
(з історичних причин пробіл дозволено закодувати як +
).
Гарна новина полягає в тому, що URL
об’єкт виконає всі перетворення автоматично. Нам потрібно тільки передати всі параметри, а потім перетворити URL
в рядок:
// для прикладу використано кириличні символи
let url = new URL('https://uk.wikipedia.org/wiki/Тест');
url.searchParams.set('key', 'ї');
alert(url); // https://uk.wikipedia.org/wiki/%D0%A2%D0%B5%D1%81%D1%82?key=%D1%97
Як бачите, і Тест
у шляху, і параметр ї
закодовано.
URL-адреса стала довшою, бо кожен кириличний символ представлено двома байтами в UTF-8, тому там дві групи символів %..
.
Кодування рядків
До появи URL
об’єктів, розробники використовували рядки для URL-адрес.
Наразі, зручніше використовувати URL
об’єкти, але рядки все ще можна використовувати. У більшості випадків, використання рядків потребує менше коду.
Слід зауважити, якщо ми використовуємо рядки, то закодувати та декодувати символи нам потрібно вручну.
Для цього є вбудовані функції:
- encodeURI – закодувати URL-адресу повністю.
- decodeURI – розкодувати її.
- encodeURIComponent – закодувати частину URL-адреси, наприклад, параметри пошуку, шлях чи хеш.
- decodeURIComponent – розкодувати відповідну частину.
Може виникнути природне питання: “Яка різниця між encodeURIComponent
та encodeURI
? Коли використовувати яку?”
Це легше зрозуміти, якщо подивитися на URL-адресу, що показано розділеною на частини вище.
https://site.com:8080/path/page?p1=v1&p2=v2#hash
Як бачимо, символи :
, ?
, =
, &
, #
дозволено безпосередньо використовувати в URL.
…На противагу цьому, якщо ми поглянемо тільки на параметри пошуку URL, то використані там символи повинні бути закодовані, щоб не зламати форматування.
encodeURI
кодує тільки символи, що заборонені до використання в URL.encodeURIComponent
закодує деякі символи та символи:#
,$
,&
,+
,,
,/
,:
,;
,=
,?
та@
.
Отже, для кодування всього URL можна використати encodeURI
:
// використання кириличних символі в шляху url
let url = encodeURI('http://site.com/привіт');
alert(url); // http://site.com/%D0%BF%D1%80%D0%B8%D0%B2%D1%96%D1%82
…Проте, для URL параметрів нам знадобиться використати encodeURIComponent
:
let music = encodeURIComponent('Rock&Roll');
let url = `https://google.com/search?q=${music}`;
alert(url); // https://google.com/search?q=Rock%26Roll
Порівняймо його з encodeURI
:
let music = encodeURI('Rock&Roll');
let url = `https://google.com/search?q=${music}`;
alert(url); // https://google.com/search?q=Rock&Roll
Як бачимо, encodeURI
не кодує символ &
, оскільки це дозволений для використання в URL.
Але нам потрібно закодувати &
всередині параметрів пошуку, інакше ми отримаємо q=Rock&Roll
, що означатиме q=Rock
та незрозумілий параметр Roll
. Не те, що ми очікували.
Нам слід використовувати тільки encodeURIComponent
з параметрами пошуку для правильного вставлення в рядок URL. Для повної безпеки, слід кодувати ім’я та значення параметрів, якщо ми не можемо бути повністю впевненими, що вони містять тільки дозволені символи.
URL
Класи URL та URLSearchParams ґрунтуються на останній специфікації URL: RFC3986, але функції encode*
використовують застарілу версію RFC2396.
Існують деякі відмінності, як от IPv6 адреси кодуються по-іншому:
// valid url with IPv6 address
let url = 'http://[2607:f8b0:4005:802::1007]/';
alert(encodeURI(url)); // http://%5B2607:f8b0:4005:802::1007%5D/
alert(new URL(url)); // http://[2607:f8b0:4005:802::1007]/
Як бачимо, encodeURI
замінила квадратні дужки [...]
, що є помилкою, причиною є те, що IPv6 адреси ще не існували в часи створення стандарту RFC2396 (серпень 1998).
Такі випадки рідко трапляються, функції encode*
добре справляються в більшості випадків.