Bir URL'nin her parçası ve neler içerebileceği
Bir URL, hangi protokolün konuşulacağını, bunun hangi makineye karşı konuşulacağını ve ne isteneceğini söyleyen tek bir dizedir. Bir URL'yi doğru okumak büyük ölçüde her parçanın nerede bittiğini bilmekle ilgilidir, çünkü ayraçlar tek karakterdir ve ilk görülen kazanır.
https://alex:s3cret@www.example.co.uk:8443/docs/intro?lang=en&page=2#notes
│ │ │ │ │ │ └─ fragment
│ │ │ │ │ └──────────────── query
│ │ │ │ └──────────────────────────── path
│ │ │ └──────────────────────────────── port
│ │ └────────────────────────────────────────────────── host
│ └────────────────────────────────────────────────────────────── userinfo
└────────────────────────────────────────────────────────────────────── scheme
Parçalar
| Parça | Ayracı | Ne işe yarar | Sunucuya ulaşır mı |
|---|---|---|---|
| Şema | ilk : karakterinde biter | Hangi protokol ve geri kalanı için hangi kurallar geçerli | Bağlantıyı belirler |
| Kullanıcı bilgisi | // sonrasında başlar, @ ile biter | Kimlik bilgileri; http ve https için uzun süredir kullanımdan kaldırılmış | Yalnızca istemci göndermeyi seçerse |
| Host | :, /, ? veya # ile biter | Çözümlenip bağlanılacak alan adı ya da IP adresi | Evet, Host başlığında |
| Port | : sonrasında başlar, /, ? veya # ile biter | TCP portu; http için varsayılan 80, https için 443 | Bağlantı için kullanılır |
| Yol | / ile başlar, ? veya # ile biter | O host üzerindeki hangi kaynak | Evet, istek satırında |
| Sorgu | ? ile başlar, # ile biter | O kaynağa verilen parametreler | Evet, istek satırında |
| Fragment | # ile başlar, sona kadar sürer | Kaynağın içindeki bir konum | Hayır |
Host ile port birlikte authority bölümünü oluşturur. Fragment istisnadır: istek kurulmadan önce ayrılır, dolayısıyla sunucu onu hiçbir zaman görmez. Tarayıcılar bunu çapa bağlantıları ve istemci tarafı yönlendirme için kullanır; bazı kimlik doğrulama akışları da tokenlar sunucu günlüklerinde hiç görünmesin diye onları bilerek fragment içinde döndürür. Yine de tarayıcı geçmişine yazılır, yani gizli değildir, yalnızca gönderilmez.
Ayrılmış ve ayrılmamış karakterler
Yüzde kodlama bir baytı, karakterin UTF-8 baytlarını kullanarak % ve ardından iki onaltılık basamak biçiminde yazar. é karakteri %C3%A9 olur: iki bayt, iki kaçış dizisi.
Harf ve rakamların yanında dört karakter ayrılmamış sayılır ve hiçbir yerde kodlanması gerekmez: - . _ ~. Geri kalan her şey ya ayrılmıştır, yani URL'nin bir yerinde yapısal bir görevi vardır, ya da kodlanmak zorundadır. Ayrılmış küme şudur: : / ? # [ ] @ ve ! $ & ' ( ) * + , ; =.
"Ayrılmış" sözcüğü "her zaman yasak" demek değildir. Karakterin bir parçada ayraç olduğu anlamına gelir ve yalnızca ayraç olarak okunacağı parçalarda kodlanması gerekir.
| Karakter | Yol parçası içinde | Sorgu değeri içinde |
|---|---|---|
| Boşluk | %20, her zaman | %20 veya + |
/ | %2F, yoksa parçayı böler | Olduğu gibi geçerli |
? | %3F, yoksa yol orada biter | Olduğu gibi geçerli |
# | %23, her zaman | %23, her zaman |
& ve = | Oldukları gibi geçerli | %26 ve %3D, yoksa çift bölünür |
+ | Geçerli, artı anlamına gelir | %2B, yoksa boşluk olarak çözülebilir |
Pratik kural budur: içinde bulunduğunuz parçayı sonlandıracak karakteri kodlayın. Yoldaki bir boşluk %20 olmak zorundadır, çünkü ham boşluk çoğu ayrıştırıcıda URL'yi bitirir; sorgu değerindeki bir boşluk ise %20 ya da eski + olabilir. Bunu yapmanın güvenilir yolu bir URL Encoder kullanmaktır, çünkü URL'nin tamamını kodlamak ile tek bir bileşeni kodlamak farklı işlemlerdir ve neredeyse her zaman istenen ikincisidir.
Sorgu dizeleri bir gelenektir
Şartname yalnızca sorgunun ? ile # arasındaki her şey olduğunu ve izin verilen karakterlerden oluştuğunu söyler. key=value&key=value biçimi URI standardından değil, HTML form kodlamasından gelir. Bir sunucunun ?a:1;b:2 ifadesini dilediği gibi ayrıştırmasını engelleyen hiçbir şey yoktur.
Biçim bir gelenek olduğu için tekrarlanan anahtarların tanımlı bir anlamı yoktur ve her yığın kendi cevabını seçmiştir:
?id=1&id=2 karşısındaki davranış | Nerede |
|---|---|
| Liste olarak her iki değer | Python parse_qs, Node querystring, Express |
| Yalnızca ilk değer | Go Query().Get, Java getParameter |
| Yalnızca son değer | PHP, Rails |
1,2 olarak birleştirilir | ASP.NET istek koleksiyonları |
Diziler de aynı sorunu devralır. ids=1&ids=2, ids[]=1&ids[]=2, ids[0]=1&ids[1]=2 ve ids=1,2 biçimlerinin hepsi yaygın kullanımdadır ve hangisinin anlaşıldığına yalnızca sunucu karar verir. Köşeli parantez gösterimi tam anlamıyla geçerli olmak için kodlanmalıdır (ids%5B%5D=1), gerçi çoğu sunucu ham parantezleri kabul eder. Alıcı tarafın belgelediği biçimi seçin, sonra tutarlı kalın.
Artı işareti kendi uyarısını hak eder. Form kodlamalı bir istek gövdesi olan application/x-www-form-urlencoded verisinde + boşluk demektir. URL yolunda gerçek bir artı demektir. Sorgu dizesinde ise ayrıştırıcıya bağlıdır ve çoğu web çatısı orada form çözümlemesi uygular, dolayısıyla + sessizce boşluğa dönüşür. Standart Base64 çıktısı ya da telefon numarası gibi meşru biçimde artı içerebilen her değer %2B olarak gönderilmelidir.
Göreli referanslar
Göreli bir referans, temel URL'nin son / karakterinden sonraki her şeyin değiştirilmesiyle çözülür. Kuralın tamamı bu son eğik çizgidir ve sondaki eğik çizginin neden önemli olduğunu da bu açıklar.
| Temel | Referans | Sonuç |
|---|---|---|
https://ex.com/docs/intro | guide | https://ex.com/docs/guide |
https://ex.com/docs/intro/ | guide | https://ex.com/docs/intro/guide |
https://ex.com/docs/intro | /guide | https://ex.com/guide |
https://ex.com/docs/intro/ | ../guide | https://ex.com/docs/guide |
https://ex.com/docs/intro?a=1 | ?b=2 | https://ex.com/docs/intro?b=2 |
https://ex.com/docs/intro?a=1 | #top | https://ex.com/docs/intro?a=1#top |
https://ex.com/docs/intro | //cdn.ex.com/x.js | https://cdn.ex.com/x.js |
Son satır şema göreli bir referanstır: baştaki iki eğik çizgi temelin şemasını korur ve authority bölümünü değiştirir. ? ile başlayan bir referans yolu korur ve eski sorguyu atar; # ile başlayan ise ikisini de korur.
İki URL ne zaman aynı kaynaktır
Şema ve host büyük küçük harfe duyarsızdır, bu yüzden HTTPS://Example.COM ve https://example.com tek bir adrestir. Standart açısından host'tan sonraki her şey büyük küçük harfe duyarlıdır, belirli bir sunucu harf durumunu yok saymayı seçse bile.
Şu çiftler eşdeğerdir:
https://example.com:443/avehttps://example.com/a, çünkü port varsayılan olandırhttps://example.comvehttps://example.com/, çünkü boş yol kök demektir/a/%7Euserve/a/~user, çünkü~ayrılmamıştır ve onu yüzde kodlamak hiçbir şeyi değiştirmez
Şu çiftler eşdeğer değildir:
/docsve/docs/, bunlar farklı kaynaklardır, gerçi çoğu sunucu birinden diğerine yönlendirir/p?a=1&b=2ve/p?b=2&a=1, çünkü parametre sırası dizenin bir parçasıdır/index.htmlve/, sunucu aksini söylemedikçe
Önbellekler ve CDN'ler tam baytlar üzerinden anahtar üretir, dolayısıyla eklenen bir izleme parametresi ya da sırası değişmiş bir sorgu, önbellekteki tek nesneyi ikiye böler ve isabet oranını yarıya indirir. Arama motorları, seçilen tek biçimi işaret eden bir canonical bağlantı olmadıkça bu varyantları yinelenen sayfa sayar. Çözüm tek bir biçim seçmek, geri kalanını 301 ile ona yönlendirmek ve yanıtı değiştirmeyen parametreleri ayıklamaktır.
Uzunluk, günlükler ve gizlilik
Şartnamede uzunluk sınırı yoktur, ama başka her yerde sınır vardır. Yaygın sunucu varsayılanları istek satırının tamamını yaklaşık 8 KB ile sınırlar, bazı vekil sunucular ve cihazlar 4 KB ile, eski istemciler ise 2 KB dolayında. E-posta istemcilerinden, QR kodlarından ve bağlantı kısaltıcılardan sağ çıkması gereken her şey için en güvenlisi yaklaşık 2000 karakterin altında kalmaktır.
URL'leri kısa tutmak için daha güçlü gerekçe, sorgu dizesinin gizli olmamasıdır. Erişim günlüklerine yazılır, Referer başlığıyla üçüncü taraflara geçer, tarayıcı geçmişinde tutulur, yer imleriyle kaydedilir ve biri bağlantıyı paylaştığında kopyalanır. Bu yüzden oturum tokenları, parola sıfırlama kodları, API anahtarları ve kişisel veriler oraya ait değildir. Büyük ya da hassas veriler, pratikte boyut tavanı olmayan ve varsayılan olarak günlüğe yazılmayan istek gövdesine konur.
Bir bağlantıyı tıklamadan önce okumak
Authority bölümü :// sonrasında başlar ve ilk /, ? veya # karakterinde biter. Önce o aralığı okuyun, sonra onun son iki ya da üç etiketini okuyun. Gerçek host odur ve solundaki hiçbir şey onu değiştirmez.
https://www.paypal.com@198.51.100.7/secure/login
^^^^^^^^^^^^^^ ^^^^^^^^^^^^
userinfo real host
Tanınması gereken yaygın süslemeler:
- Bir
@işaretinden önceki metin kullanıcı bilgisidir, asla host değildir ve herhangi bir marka adı olabilir. paypal.com.secure-login.exampleadresisecure-login.examplealan adının bir alt alanıdır. Etiketler sağdan sola okunur.https://short.example/https://www.bank.com/loginikna edici görünen bütün bir URL'yi yola yerleştirir.xn--ile başlayan bir host Punycode'dur, yani IDNA'nın ürettiği, uluslararasılaştırılmış bir alan adının ASCII biçimidir.münchen.dehat üzerindexn--mnchen-3ya.deolarak gider ve bu meşrudur, ama aynı mekanizma homograflara da olanak tanır: Kirilа(U+0430) Latinaile görsel olarak birebir aynıdır ve onu kullanan bir alan adıxn--pple-43d.combenzeri bir şeye kodlanır. Bir etiket birden çok yazı sistemini karıştırdığında tarayıcılar Punycode biçimini gösterir, gerçi kurallar değişkendir ve bir garanti değildir.- Bir host içindeki
%2Fya da%40gibi kodlanmış ayraçlar, ayrıştırıcıyı şaşırtmaya yönelik kasıtlı girişimlerdir.
Bağlantıyı bir URL Parser'a yapıştırmak konuyu tek adımda çözer, çünkü gerçek bir ayrıştırıcı tarayıcının uygulayacağı ilk ayraç kazanır kuralını uygular ve host'u tek başına gösterir. Çok sayıda bağlantıyı aynı anda denetlemek içinse, hangilerinin gerçekten beklediğiniz authority'ye sahip olduğunu doğrulamanın hızlı yolu bir Regex Tester'dır.