Bir URL'nin her parçası ve neler içerebileceği

Çalışılmış bir örnek üzerinde etiketlenmiş her URL parçası, hangi karakterin nerede yüzde kodlaması gerektirdiği, sorgu dizelerinin gerçekte nasıl davrandığı ve host konusunda yalan söyleyen bir bağlantının nasıl fark edileceğ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çaAyracıNe işe yararSunucuya ulaşır mı
Şemailk : karakterinde biterHangi protokol ve geri kalanı için hangi kurallar geçerliBağlantıyı belirler
Kullanıcı bilgisi// sonrasında başlar, @ ile biterKimlik 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 adresiEvet, Host başlığında
Port: sonrasında başlar, /, ? veya # ile biterTCP portu; http için varsayılan 80, https için 443Bağlantı için kullanılır
Yol/ ile başlar, ? veya # ile biterO host üzerindeki hangi kaynakEvet, istek satırında
Sorgu? ile başlar, # ile biterO kaynağa verilen parametrelerEvet, istek satırında
Fragment# ile başlar, sona kadar sürerKaynağın içindeki bir konumHayı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.

KarakterYol parçası içindeSorgu değeri içinde
Boşluk%20, her zaman%20 veya +
/%2F, yoksa parçayı bölerOlduğu gibi geçerli
?%3F, yoksa yol orada biterOlduğ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ğerPython parse_qs, Node querystring, Express
Yalnızca ilk değerGo Query().Get, Java getParameter
Yalnızca son değerPHP, Rails
1,2 olarak birleştirilirASP.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.

TemelReferansSonuç
https://ex.com/docs/introguidehttps://ex.com/docs/guide
https://ex.com/docs/intro/guidehttps://ex.com/docs/intro/guide
https://ex.com/docs/intro/guidehttps://ex.com/guide
https://ex.com/docs/intro/../guidehttps://ex.com/docs/guide
https://ex.com/docs/intro?a=1?b=2https://ex.com/docs/intro?b=2
https://ex.com/docs/intro?a=1#tophttps://ex.com/docs/intro?a=1#top
https://ex.com/docs/intro//cdn.ex.com/x.jshttps://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/a ve https://example.com/a, çünkü port varsayılan olandır
  • https://example.com ve https://example.com/, çünkü boş yol kök demektir
  • /a/%7Euser ve /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:

  • /docs ve /docs/, bunlar farklı kaynaklardır, gerçi çoğu sunucu birinden diğerine yönlendirir
  • /p?a=1&b=2 ve /p?b=2&a=1, çünkü parametre sırası dizenin bir parçasıdır
  • /index.html ve /, 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.example adresi secure-login.example alan adının bir alt alanıdır. Etiketler sağdan sola okunur.
  • https://short.example/https://www.bank.com/login ikna 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.de hat üzerinde xn--mnchen-3ya.de olarak gider ve bu meşrudur, ama aynı mekanizma homograflara da olanak tanır: Kiril а (U+0430) Latin a ile görsel olarak birebir aynıdır ve onu kullanan bir alan adı xn--pple-43d.com benzeri 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 %2F ya da %40 gibi 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.