Що таке розбір URL?
Розбір URL — це процес розкладання Uniform Resource Locator на окремі складові: протокол (схема), hostname, порт, шлях, параметри запиту та ідентифікатор фрагмента. Кожен URL відповідає структурі, визначеній RFC 3986 та стандартом WHATWG URL. Парсер URL зчитує вихідний рядок, визначає кожен сегмент за символами-роздільниками (://, :, /, ?, #, &, =) і повертає їх як окремі, доступні поля.
Браузери виконують розбір URL щоразу, коли ви вводите адресу або натискаєте посилання. Конструктор URL у JavaScript, модуль urllib.parse у Python та пакет net/url у Go — всі реалізують парсери, що дотримуються одних і тих самих структурних правил. Розбір URL є оберненою операцією до URL-кодування: замість перетворення символів для безпечної передачі ви розкладаєте вже сформований URL на його складові частини.
Типовий URL на кшталт https://api.example.com:8080/v1/users?page=2&limit=10#section містить шість окремих компонентів. Символи-роздільники — ://, :, /, ?, &, =, та # — роблять розбір детермінованим: кожен із них сигналізує про межу і дозволяє парсеру витягувати поля без неоднозначності.
Навіщо використовувати онлайн-парсер URL?
Розбирати URL вручну — ненадійно, особливо якщо рядок містить закодовані символи, декілька параметрів запиту або нестандартні порти. Цей інструмент розбирає URL за допомогою того самого алгоритму, що відповідає стандарту WHATWG і використовується в браузерах, та відображає кожен компонент у зрозумілій таблиці з можливістю копіювання.
Сценарії використання парсера URL
Довідник компонентів URL
Таблиця нижче показує кожну властивість, яку повертає конструктор URL у JavaScript при розборі URL. Ті самі компоненти присутні у результаті urlparse у Python, структурі url.URL у Go та виводі parse_url у PHP, хоча назви властивостей різняться між мовами.
| Властивість | Приклад | Опис |
|---|---|---|
| protocol | https: | Scheme including the trailing colon |
| hostname | api.example.com | Domain name or IP address |
| port | 8080 | Port number (empty string if default) |
| pathname | /v1/users | Path starting with / |
| search | ?page=2&limit=10 | Query string including the leading ? |
| hash | #section | Fragment identifier including the leading # |
| origin | https://api.example.com:8080 | protocol + hostname + port |
| host | api.example.com:8080 | hostname + port |
| username | admin | Credentials before @ (rarely used in practice) |
| password | secret | Credentials before @ (avoid in production URLs) |
| href | (full URL) | The complete, serialized URL string |
Стандарт WHATWG URL vs RFC 3986
Два специфікації визначають, як слід розбирати URL. Вони збігаються в базовій структурі, але розходяться в граничних випадках — і саме це розходження зазвичай є причиною того, що браузер обробляє URL інакше, ніж ваш сервер.
На практиці більшість відмінностей виявляється при розборі URL з міжнародними доменними іменами (IDN), відсутніми схемами або незвичними символами. Парсер WHATWG автоматично перетворює IDN-hostname на Punycode, тоді як строгі парсери RFC 3986 можуть відхиляти їх. Якщо ви вставляєте URL у цей інструмент і отримуєте результати, відмінні від тих, що видає ваш серверний код, найімовірніша причина — відмінність між WHATWG та RFC.
Приклади коду
У кожній популярній мові є вбудований парсер URL. Наведені нижче приклади розбирають один і той самий URL та витягують його компоненти. Зверніть увагу на незначні відмінності в назвах між мовами: Python використовує scheme замість protocol, а Go — RawQuery замість search.
const url = new URL('https://api.example.com:8080/v1/users?page=2&limit=10#section')
url.protocol // → "https:"
url.hostname // → "api.example.com"
url.port // → "8080"
url.pathname // → "/v1/users"
url.search // → "?page=2&limit=10"
url.hash // → "#section"
// Iterate over query parameters
for (const [key, value] of url.searchParams) {
console.log(`${key} = ${value}`)
}
// → "page = 2"
// → "limit = 10"
// Modify and re-serialize
url.searchParams.set('page', '3')
url.toString()
// → "https://api.example.com:8080/v1/users?page=3&limit=10#section"from urllib.parse import urlparse, parse_qs
result = urlparse('https://api.example.com:8080/v1/users?page=2&limit=10#section')
result.scheme # → 'https'
result.hostname # → 'api.example.com'
result.port # → 8080
result.path # → '/v1/users'
result.query # → 'page=2&limit=10'
result.fragment # → 'section'
# Parse query string into a dict
params = parse_qs(result.query)
params['page'] # → ['2']
params['limit'] # → ['10']
# Reconstruct with modifications
from urllib.parse import urlencode, urlunparse
new_query = urlencode({'page': '3', 'limit': '10'})
urlunparse(result._replace(query=new_query))
# → 'https://api.example.com:8080/v1/users?page=3&limit=10#section'package main
import (
"fmt"
"net/url"
)
func main() {
u, err := url.Parse("https://api.example.com:8080/v1/users?page=2&limit=10#section")
if err != nil {
panic(err)
}
fmt.Println(u.Scheme) // → "https"
fmt.Println(u.Hostname()) // → "api.example.com"
fmt.Println(u.Port()) // → "8080"
fmt.Println(u.Path) // → "/v1/users"
fmt.Println(u.RawQuery) // → "page=2&limit=10"
fmt.Println(u.Fragment) // → "section"
// Query params as map
q := u.Query()
fmt.Println(q.Get("page")) // → "2"
fmt.Println(q.Get("limit")) // → "10"
}<?php $url = 'https://api.example.com:8080/v1/users?page=2&limit=10#section'; $parts = parse_url($url); $parts['scheme']; // → "https" $parts['host']; // → "api.example.com" $parts['port']; // → 8080 $parts['path']; // → "/v1/users" $parts['query']; // → "page=2&limit=10" $parts['fragment']; // → "section" // Parse query string into an array parse_str($parts['query'], $params); $params['page']; // → "2" $params['limit']; // → "10"