URL об’єкти
Вбудований клас URL надає зручний інтерфейс для створення та розбирання URL на частини.
Зазвичай, щоб зробити мережевий запит, достатньо передати лише рядок з адресою, передавати саме екземпляр класу URL не має жодної потреби. Тому нас ніхто не зобов’язує використовувати клас URL. Але іноді це може стати в нагоді.
Створення URL
Синтаксис для створення URL об’єктів:
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* добре справляються в більшості випадків.