Cos'è il parsing degli URL?
Il parsing degli URL è il processo di scomposizione di un Uniform Resource Locator nelle sue componenti individuali: protocollo (schema), hostname, porta, percorso, parametri query e identificatore di frammento. Ogni URL segue una struttura definita da RFC 3986 e dallo WHATWG URL Standard. Un parser URL legge la stringa grezza, identifica ogni segmento tramite i suoi caratteri delimitatori (://, :, /, ?, #, &, =) e restituisce ciascuno come campo separato e accessibile.
I browser eseguono il parsing degli URL ogni volta che digiti un indirizzo o clicchi su un link. Il costruttore JavaScript URL, il modulo urllib.parse di Python e il pacchetto net/url di Go implementano tutti parser che seguono le stesse regole strutturali. Analizzare un URL è l'operazione inversa della codifica URL: invece di trasformare i caratteri per un trasporto sicuro, si scompone un URL già formato nelle parti che lo compongono.
Un URL tipico come https://api.example.com:8080/v1/users?page=2&limit=10#section contiene sei componenti distinte. I caratteri delimitatori — ://, :, /, ?, &, =, e # — rendono il parsing deterministico: ognuno segnala un confine e permette al parser di estrarre i campi senza ambiguità.
Perché usare un analizzatore URL online?
Dividere manualmente un URL a occhio è soggetto a errori, specialmente quando la stringa contiene caratteri codificati, più parametri query o porte non standard. Questo strumento analizza l'URL utilizzando lo stesso algoritmo conforme a WHATWG usato dai browser e mostra ogni componente in una tabella chiara e copiabile.
Casi d'uso dell'analizzatore URL
Riferimento alle componenti URL
La tabella seguente mostra ogni proprietà restituita dal costruttore JavaScript URL durante il parsing di un URL. Le stesse componenti esistono nel risultato di urlparse di Python, nella struct url.URL di Go e nell'output di parse_url di PHP, sebbene i nomi delle proprietà differiscano tra i linguaggi.
| Proprietà | Esempio | Descrizione |
|---|---|---|
| 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 Standard vs RFC 3986
Due specifiche definiscono come gli URL devono essere analizzati. Concordano sulla struttura di base ma divergono nei casi limite — e quella divergenza è solitamente la causa quando il browser gestisce un URL diversamente rispetto al tuo server.
In pratica, la maggior parte delle differenze emerge quando si analizzano URL con nomi di dominio internazionali (IDN), schemi mancanti o caratteri insoliti. Il parser WHATWG converte automaticamente gli hostname IDN in Punycode, mentre i parser RFC 3986 stretti possono rifiutarli. Se incolli un URL in questo strumento e ottieni risultati diversi rispetto al codice lato server, la differenza tra WHATWG e RFC è la causa più probabile.
Esempi di codice
Ogni linguaggio principale ha un parser URL integrato. Gli esempi seguenti analizzano lo stesso URL ed estraggono le sue componenti. Nota le piccole differenze nei nomi tra i linguaggi: Python usa scheme invece di protocol, e Go espone RawQuery invece di 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"