تجزیه URL چیست؟
تجزیه URL فرآیند تقسیم یک Uniform Resource Locator به اجزای جداگانه آن است: پروتکل (scheme)، نام میزبان، پورت، مسیر، پارامترهای کوئری و شناسه قطعه. هر 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
جدول زیر هر خاصیتی را که سازنده JavaScript URL هنگام تجزیه یک URL بازمیگرداند نشان میدهد. همین اجزا در نتیجه urlparse پایتون، ساختار 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 در مقابل RFC 3986
دو مشخصه نحوه تجزیه URLها را تعریف میکنند. در ساختار اصلی توافق دارند اما در موارد مرزی متفاوت عمل میکنند — و این تفاوت معمولاً همان دلیلی است که مرورگر شما یک URL را متفاوت از سرورتان مدیریت میکند.
در عمل، بیشتر تفاوتها هنگام تجزیه URLهایی با نامهای دامنه بینالمللی (IDN)، schemeهای ناقص یا کاراکترهای غیرمعمول ظاهر میشوند. تجزیهگر WHATWG نامهای میزبان IDN را بهطور خودکار به Punycode تبدیل میکند، در حالی که تجزیهگرهای سختگیر RFC 3986 ممکن است آنها را رد کنند. اگر URLای را در این ابزار جایگذاری کنید و نتایجی متفاوت از کد سمت سرور مشاهده کنید، احتمالاً تفاوت WHATWG در مقابل RFC دلیل اصلی است.
نمونههای کد
هر زبان اصلی یک تجزیهگر URL داخلی دارد. مثالهای زیر همان URL را تجزیه میکنند و اجزای آن را استخراج مینمایند. توجه داشته باشید که نامگذاری در زبانهای مختلف کمی متفاوت است: Python از scheme بهجای protocol استفاده میکند و Go بهجای search، RawQuery را در معرض دید قرار میدهد.
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"