ما هو تحليل URL؟
تحليل URL هو عملية تفكيك محدد موقع الموارد الموحّد (Uniform Resource Locator) إلى مكوناته الفردية: البروتوكول (المخطط)، واسم المضيف، والمنفذ، والمسار، وبارامترات الاستعلام، ومعرّف الجزء. كل URL يتبع بنية محددة وفق RFC 3986 ومعيار WHATWG URL. يقرأ محلل URL السلسلة الخام، ويتعرف على كل قطعة من خلال محارف الفصل (://، :، /، ?، #، &، =)، ويعيدها كحقول منفصلة يمكن الوصول إليها.
تُجري المتصفحات تحليل URL في كل مرة تكتب فيها عنوانًا أو تضغط على رابط. مُنشئ URL في JavaScript، ووحدة urllib.parse في Python، وحزمة net/url في Go — كلها تُنفّذ محللات تتبع القواعد البنيوية ذاتها. تحليل URL هو عكس ترميز URL: بدلًا من تحويل الأحرف لنقل آمن، تُفكّك URL مُشكَّلة مسبقًا إلى الأجزاء التي تُكوّنها.
رابط نموذجي مثل https://api.example.com:8080/v1/users?page=2&limit=10#section يحتوي على ستة مكونات مستقلة. محارف الفصل — ://، :، /، ?، &، =، و# — هي ما يجعل التحليل حتميًا: كل منها يُشير إلى حدٍّ ويُتيح للمحلل استخراج الحقول دون غموض.
لماذا تستخدم محلل URL أونلاين؟
تقسيم URL يدويًا بالعين مُعرَّض للخطأ، لا سيما حين تحتوي السلسلة على أحرف مُرمَّزة أو بارامترات استعلام متعددة أو منافذ غير قياسية. تحلّل هذه الأداة URL باستخدام الخوارزمية المتوافقة مع WHATWG التي تستخدمها المتصفحات، وتعرض كل مكون في جدول واضح قابل للنسخ.
حالات استخدام محلل URL
مرجع مكونات URL
يُبيّن الجدول أدناه كل خاصية يُعيدها مُنشئ URL في JavaScript عند تحليل رابط. المكونات ذاتها موجودة في نتيجة 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 مقابل RFC 3986
يُحدّد مرجعان كيفية تحليل URL. يتفقان على البنية الأساسية لكنهما يتباينان في الحالات الطرفية — وهذا التباين عادةً ما يكون السبب حين يتعامل متصفحك مع رابط بشكل مختلف عما يفعله خادمك.
عمليًا، تظهر معظم الفروق عند تحليل روابط تحتوي على أسماء نطاقات دولية (IDN)، أو مخططات مفقودة، أو أحرف غير معتادة. يُحوّل محلل WHATWG أسماء مضيفي IDN إلى Punycode تلقائيًا، في حين قد يرفضها محللو RFC 3986 الصارمون. إذا لصقت رابطًا في هذه الأداة ورأيت نتائج مختلفة عما يُنتجه كودك من جانب الخادم، فالفرق بين WHATWG وRFC هو السبب الأرجح.
أمثلة على الكود
كل لغة برمجة رئيسية تمتلك محلل 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"