URL Kodlama ve Çözme: Geliştiriciler için Yüzde Kodlaması Rehberi
Bir sunucu kayıt dosyasını izlerken bir query string içinde şunu görüyorsunuz: %E4%BD%A0%E5%A5%BD. Bozuk veri mi? Hata mı? Hiçbiri — bu, Çince 你好 karakterlerinin önce her birinin üç UTF-8 baytına dönüştürülüp ardından URL için güvenli bir biçimde yüzde kodlaması ile kodlanmış halidir. Her web geliştiricisi sonunda bu duvara çarpar: bir şey bozuk görünür, ama URL tam tasarlandığı gibi çalışmaktadır.
URL kodlaması — resmi adıyla yüzde kodlaması — özel karakterleri URL’ler için güvenli hale getiren mekanizmadır. Bu rehber, mekanizmanın bayt düzeyinde nasıl çalıştığını, ne zaman encodeURI yerine encodeURIComponent kullanmak gerektiğini, dört dilde doğru kodlamanın nasıl yapılacağını ve deneyimli geliştiricilerin bile takıldığı hataları ele alır.
Kodlama ve çözme işlemini gerçek zamanlı takip etmek için herhangi bir URL’yi URL Koder ve Çözücü aracımıza yapıştırın.
URL Kodlaması (Yüzde Kodlaması) Nedir?
Bir URL, ASCII karakterlerinin yalnızca küçük bir alt kümesini içerebilir. Harfler, rakamlar ve birkaç sembol internet üzerinde sorunsuz biçimde dolaşır. Geri kalan her şey — boşluklar, ve işaretleri, Çince metin, emoji — URL’lerin taşıyabileceği bir biçime dönüştürülmelidir.
Yüzde kodlaması her güvensiz baytı % işareti ile ardından gelen iki onaltılık basamakla değiştirir. Bir boşluk %20 olur. Bir ve işareti %26 olur. Adı bu % ön ekinden gelir.
Kurallar RFC 3986 belgesinde yer alır; 2005’te yayımlanmıştır ve hâlâ geçerli standarttır. RFC 2396’nın yerini almış, hangi karakterlerin güvenli, hangilerinin ayrılmış olduğunun ve ASCII dışı metnin nasıl ele alınacağının tanımını sıkılaştırmıştır.
Hızlı örnekler:
| Girdi | Kodlanmış | Neden |
|---|---|---|
hello world | hello%20world | URL’lerde boşluğa izin verilmez |
price=10&tax=2 | price%3D10%26tax%3D2 | = ve & yapısal anlam taşır |
中 | %E4%B8%AD | ASCII dışı → UTF-8 baytları → yüzde kodlu |
🚀 | %F0%9F%9A%80 | Emoji → 4 UTF-8 baytı → yüzde kodlu |
Hangi Karakterler Kodlama Gerektirir?
RFC 3986 karakterleri üç gruba ayırır.
Ayrılmamış Karakterler (Hiçbir Zaman Kodlanmaz)
Bu 66 karakter URL’nin herhangi bir bölümünde olduğu gibi geçer:
A-Z a-z 0-9 - . _ ~
Harfler, rakamlar, kısa çizgi, nokta, alt çizgi, tilde. Listenin tamamı budur.
Ayrılmış Karakterler (Bağlama Bağlı)
Bu karakterler URL’lerde yapısal ayraç görevi görür:
| Karakter | URL yapısındaki rol |
|---|---|
: | Şemayı yetki bölümünden ayırır (https:) |
/ | Yol parçalarını ayırır |
? | Query string’i başlatır |
# | Parça (fragment) başlatır |
& | Sorgu parametrelerini ayırır |
= | Parametre anahtarını değerden ayırır |
@ | Kullanıcı bilgisini sunucudan ayırır |
+ ! $ ' ( ) * , ; [ ] | Çeşitli ayrılmış roller |
Kural: ayrılmış bir karakter yapısal amacına hizmet ediyorsa olduğu gibi bırakın. Veri olarak görünüyorsa (örneğin bir parametre değerinin içinde), kodlayın.
Diğer Her Şey (Her Zaman Kodlanır)
Boşluklar, açılı parantezler, süslü parantezler, dikey çizgiler, ters bölü işaretleri ve ASCII dışı karakterler (Çince, Arapça, emoji) yüzde kodlamasından geçirilmelidir.
Bir incelik var: RFC 3986 boşlukları %20 olarak kodlar, ama HTML form gönderimleri + kullanır. Bu çatışmayı aşağıdaki “%20 ile +” bölümünde ele alıyoruz.
URL Kodlaması Aslında Nasıl Çalışır: UTF-8 Pipeline
ASCII karakterler için kodlama basittir: bayt değerini onaltılıkta arayın, başına % ekleyin. Bir boşluk (bayt değeri 32, hex 20) %20 olur.
ASCII dışı metinler için kodlamanın üç adımı vardır:
Adım 1 — Karakterden Unicode kod noktasına.
é karakteri U+00E9 kod noktasına eşlenir. 🚀 emojisi U+1F680’e eşlenir.
Adım 2 — Kod noktasından UTF-8 baytlarına.
UTF-8, kod noktası aralığına bağlı olarak 1 ila 4 bayt kullanır. é (U+00E9) iki bayt olur: 0xC3 0xA9. Roket emojisi (U+1F680) dört bayt olur: 0xF0 0x9F 0x9A 0x80.
Adım 3 — Her bayt için %XX.
2. adımdan gelen her bayt kendi yüzde kodlu üçlüsünü alır.
Çeşitli karakter tipleri için tüm pipeline aşağıdadır:
| Karakter | Kod Noktası | UTF-8 Baytları | Kodlanmış | Boyut çarpanı |
|---|---|---|---|---|
A | U+0041 | 41 | A (kodlanmaz) | 1× |
| boşluk | U+0020 | 20 | %20 | 3× |
é | U+00E9 | C3 A9 | %C3%A9 | 6× |
中 | U+4E2D | E4 B8 AD | %E4%B8%AD | 9× |
🚀 | U+1F680 | F0 9F 9A 80 | %F0%9F%9A%80 | 12× |
Bunu JavaScript ile kendiniz doğrulayabilirsiniz:
const char = '中';
const encoded = encodeURIComponent(char);
console.log(encoded); // '%E4%B8%AD'
// Baytları izle
const bytes = new TextEncoder().encode(char);
console.log([...bytes].map(b => '%' + b.toString(16).toUpperCase()).join(''));
// '%E4%B8%AD' — eşleşiyor
Bu genişleme, aşağıdaki “URL Uzunluk Sınırları” bölümünde ele aldığımız kısıtlar açısından önemlidir. 20 Çince karakter içeren bir URL, 180 karakterlik yüzde kodlu metin ekler.
encodeURI ile encodeURIComponent — Doğru Fonksiyonu Seçmek
Bu iki JavaScript fonksiyonu sürekli karıştırılır. Benzer görünürler ama çok farklı karakter kümelerini kodlarlar.
encodeURI() | encodeURIComponent() | |
|---|---|---|
| Amaç | Tam bir URL’yi kodlar | Tek bir bileşeni kodlar (parametre anahtarı veya değeri) |
| Korur | : / ? # & = @ + $ , | Bunların hiçbirini korumaz |
| Kodlar | Boşluklar, ASCII dışı, bazı noktalama işaretleri | A-Z a-z 0-9 - _ . ~ ! ' ( ) * dışındaki her şeyi |
| Ne zaman kullanılır | Yolda boşluk veya Unicode bulunan tam bir URL’niz varsa | Kullanıcı girdisinden sorgu parametreleri oluşturuyorsanız |
Düzenli olarak üretime giden bir hata:
// ❌ HATA: encodeURI & karakterini kodlamaz
const search = 'Tom & Jerry';
const bad = `https://api.example.com/search?q=${encodeURI(search)}`;
// Sonuç: https://api.example.com/search?q=Tom%20&%20Jerry
// & query string'i böler — sunucu q=Tom%20 ve ayrı bir param %20Jerry görür
// ✅ DÜZELTME: encodeURIComponent & karakterini %26 olarak kodlar
const good = `https://api.example.com/search?q=${encodeURIComponent(search)}`;
// Sonuç: https://api.example.com/search?q=Tom%20%26%20Jerry
Tereddütteyseniz encodeURIComponent() seçin. Gerçek dünyadaki URL oluşturma senaryolarının yüzde 95’i için doğru tercihtir.
URL Koder aracımızda iki modu yan yana deneyin →
Her Dilde URL Kodlaması
JavaScript (Tarayıcı ve Node.js)
// Bir parametre değerini kodla
const value = encodeURIComponent('price >= 100 & currency = €');
// 'price%20%3E%3D%20100%20%26%20currency%20%3D%20%E2%82%AC'
// Çöz
const original = decodeURIComponent(value);
// 'price >= 100 & currency = €'
// Modern yaklaşım: URLSearchParams kodlamayı otomatik halleder
const params = new URLSearchParams({ q: 'hello world', lang: '中文' });
console.log(params.toString());
// 'q=hello+world&lang=%E4%B8%AD%E6%96%87'
// Not: URLSearchParams boşluklar için + kullanır (form kodlaması)
Python
from urllib.parse import quote, unquote, urlencode
# Bir yol parçasını kodla
quote('hello world/file name.txt', safe='/')
# 'hello%20world/file%20name.txt'
# Sorgu parametrelerini kodla
urlencode({'q': '你好', 'page': '1'})
# 'q=%E4%BD%A0%E5%A5%BD&page=1'
# quote_plus boşluklar için + kullanır (form kodlaması)
from urllib.parse import quote_plus
quote_plus('hello world') # 'hello+world'
quote('hello world') # 'hello%20world'
Go
import "net/url"
// Bir sorgu değerini kodla (boşluk için + kullanır)
url.QueryEscape("hello world & more")
// "hello+world+%26+more"
// Bir yol parçasını kodla (boşluk için %20 kullanır)
url.PathEscape("hello world & more")
// "hello%20world%20&%20more"
// url.Values ile bir URL'yi güvenli biçimde inşa et
params := url.Values{}
params.Set("q", "你好世界")
params.Set("page", "1")
fmt.Println(params.Encode())
// "page=1&q=%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C"
Java
import java.net.URLEncoder;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
// Kodla (boşluk için + kullanır — Java form kodlamasını izler)
String encoded = URLEncoder.encode("hello world & more", StandardCharsets.UTF_8);
// "hello+world+%26+more"
// RFC 3986 uyumu için + karakterini %20 ile değiştir
String rfc3986 = encoded.replace("+", "%20");
// "hello%20world%20%26%20more"
// Çöz
String decoded = URLDecoder.decode(encoded, StandardCharsets.UTF_8);
// "hello world & more"
Go ve Java varsayılan olarak form kodlamasına başvurur (boşluklar + olur). RFC 3986 çıktısı için sonucu son işlemden geçirip + karakterini %20 ile değiştirin.
Üretimi Bozan Beş URL Kodlama Hatası
1. Çift Kodlama (%20 Yerine %2520)
Bir karakter dizisini kodlarsınız. Bir framework onu tekrar kodlar. %20 içindeki % %25 olur ve sunucu bir boşluk yerine düz %20 metni görür.
Belirti: URL’ler %2520, %253D veya başka %25xx desenleri içerir.
Tanı: Bir URL’deki %25, bir % karakterinin kodlandığı anlamına gelir; bu da çoğunlukla çift kodlamaya işaret eder.
Düzeltme: Önce çözün, sonra bir kez kodlayın. Kodlamadan önce girdinin zaten kodlanmış olup olmadığını denetleyin.
// Çift kodlamayı tespit et
function isDoubleEncoded(str) {
return /%25[0-9A-Fa-f]{2}/.test(str);
}
// Güvenli kodlama: önce çöz, sonra kodla
function safeEncode(str) {
try { str = decodeURIComponent(str); } catch (e) { /* kodlanmamış, sorun değil */ }
return encodeURIComponent(str);
}
2. Yol Parçalarında +
Bir geliştirici, boşluklar için + çıktısı veren bir kütüphaneyle bir dosya adını URL kodlamasından geçirir. my report.pdf dosyası my+report.pdf olur. Sunucu + karakterini düz artı işareti olarak yorumlar ve 404 döndürür.
Kural: + yalnızca query string’lerde (yani ? sonrasında) boşluk anlamına gelir. Yol parçalarında + yalnızca +’tır. Yollarda boşluklar için her zaman %20 kullanın.
3. Bozuk OAuth Yönlendirme URI’leri
Yetkilendirme URL’si şuna benzer:
https://auth.provider.com/authorize?redirect_uri=https://myapp.com/callback?code=abc&state=xyz
OAuth sunucusu redirect_uri=https://myapp.com/callback?code=abc kısmını okur ve state=xyz parçasını ayrı bir üst düzey parametre olarak işler. Kimlik doğrulama başarısız olur.
Düzeltme: Yönlendirme URI değerinin tamamını kodlayın:
const redirectUri = 'https://myapp.com/callback?code=abc&state=xyz';
const authUrl = `https://auth.provider.com/authorize?redirect_uri=${encodeURIComponent(redirectUri)}`;
// redirect_uri=https%3A%2F%2Fmyapp.com%2Fcallback%3Fcode%3Dabc%26state%3Dxyz
4. Kayıtlardaki Bozuk ASCII Dışı Metin
Sunucu kayıtları okunabilir Çince karakterler yerine %E4%BD%A0%E5%A5%BD gösterir. URL doğru biçimde kodlanmıştır; yalnızca kayıt görüntüleyiciniz yüzde kodlu dizileri çözmüyordur.
Düzeltme: Kayıtları bir çözücüden geçirin veya orijinal metni okumak için URL’yi bir URL Çözücü aracına yapıştırın.
5. API İmza Hataları
OAuth 1.0 ve AWS Signature V4 sıkı RFC 3986 kodlaması gerektirir. JavaScript’in encodeURIComponent() fonksiyonu !, ', (, ) veya * karakterlerini kodlamaz. Bu karakterler imza girdinizde görünürse imza eşleşmez.
Düzeltme: Çıktıyı son işlemden geçirin:
function rfc3986Encode(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, c =>
'%' + c.charCodeAt(0).toString(16).toUpperCase()
);
}
%20 ile + — Boşluk Kodlama İkilemi
Bir tek karakterin nasıl kodlanacağı konusunda iki standart anlaşamaz.
| Standart | Boşluk şuna dönüşür | Nerede geçerlidir |
|---|---|---|
| RFC 3986 (URI sözdizimi) | %20 | Bir URL’nin her yerinde |
application/x-www-form-urlencoded | + | HTML form gönderimlerinden gelen query string’lerde |
+ kuralı erken web tarayıcılarından kalma bir mirastır. Bir <form>, method="GET" ile gönderildiğinde tarayıcı boşlukları query string’de + olarak kodlar. HTML belirtimi bu davranışı resmileştirir.
Sorun şu: + yalnızca query string’lerde “boşluk” anlamına gelir. Yol parçalarında + düz bir artı işaretidir. Bu yüzden https://example.com/my+file.pdf, my file.pdf adlı bir dosyayı değil, my+file.pdf adlı bir dosyayı sunar.
Pratik öneri:
- URL’leri elle inşa ederken veya yol parçalarını kodlarken
%20kullanın. Her yerde çalışır. - Form gönderimlerinden gelen query string’leri ayrıştırırken
+karakterini kabul edin — framework’ünüz büyük olasılıkla bunu zaten ele alıyordur. - İki kuralı karıştırmayın. Her bileşen için bir kural seçin ve ona bağlı kalın.
URL Kodlaması ve Güvenlik
URL Kodlaması Şifreleme DEĞİLDİR
Yüzde kodlaması, kriptografik özelliği olmayan, tam tersine çevrilebilir, deterministik bir dönüşümdür. Herhangi biri %48%65%6C%6C%6F dizesini milisaniyeler içinde tekrar Hello’ya çözebilir.
Hassas verileri gizlemek için URL kodlamasını kullanmayın. İsteğin tamamını şifrelemek için HTTPS kullanın. URL’ler sunucu kayıtlarında, tarayıcı geçmişinde ve Referer header’lerinde görünür; bu yüzden hassas bilgiler URL’lerde değil, istek gövdelerinde yer almalıdır.
Open Redirect Saldırıları
Saldırganlar saf doğrulamayı aşmak için kodlanmış URL’ler kullanır. %2F%2Fevil.com içeren bir yönlendirme parametresi //evil.com olarak çözülür; tarayıcılar bunu saldırganın etki alanına işaret eden protokol-bağıl bir URL olarak yorumlar.
Savunma: Kodlanmış biçimi değil, çözülmüş URL’yi doğrulayın. Yönlendirme etki alanları için allowlist kullanın.
Çift Kodlama İstismarları
Bir WAF, gelen URL’leri <script> etiketleri için denetler. Bir saldırgan %253Cscript%253E gönderir. WAF yüzde kodlu metni görür ve geçirir. Uygulama bir kez çözer, %3Cscript%3E ortaya çıkar; ikinci bir çözme <script> üretir ve filtre aşılır.
Savunma: Güvenlik kontrolleri uygulamadan önce tüm girdiyi normalleştirin (tamamen çözün). Tek bir çözme adımına güvenmeyin.
Kimlik doğrulama tokenlarını URL’lerde ve Authorization header’lerinde taşırken karşılaşılan tuzaklar için JWT çözme rehberimize bakın.
URL Uzunluk Sınırları ve Kodlama Ne Zaman Pahalıya Mal Olur
HTTP belirtimi azami URL uzunluğu belirlemez, ama yığının her katmanı pratik sınırlar koyar.
| Katman | Sınır |
|---|---|
| Genel öneri | 2.000 karakter |
| Chrome, Firefox | ~2 MB (ama sunucular çok daha önce reddeder) |
| Apache (varsayılan) | 8.190 bayt |
| Nginx (varsayılan) | 8.192 bayt |
| IIS | 16.384 bayt (query string) |
| CDN’ler, proxy’ler | Değişken — genellikle 4.096-8.192 bayt |
Yüzde kodlaması URL’leri uzatır. Tek bir Çince karakter 1 karakterden 9 karaktere (%E4%B8%AD) çıkar. Bir emoji 12’ye genişler. Bir query string’deki iki yüz Çince karakter tek başına 1.800 karakterlik yüzde kodlu metin üretir.
Sınıra ulaştığınızda: Veriyi sorgu parametrelerinden bir POST isteği gövdesine taşıyın. Arama arayüzleri için JSON kabul eden bir POST endpoint iyi bir çözümdür.
SSS
URL kodlaması nedir ve geliştiricilerin neden buna ihtiyacı vardır?
URL kodlaması (yüzde kodlaması), URL’lerde izin verilmeyen karakterleri %XX hex dizilerine dönüştürür. URL’ler yalnızca 66 ayrılmamış ASCII karakterini destekler. Boşluklar, ve işaretleri, Unicode metin ve çoğu noktalama işareti kodlanmalıdır; aksi takdirde URL yapısını bozarlar.
encodeURI ile encodeURIComponent arasındaki fark nedir?
encodeURI() ://, /, ? ve & gibi yapısal karakterleri korurken tam bir URL’yi kodlar. encodeURIComponent() ise A-Z a-z 0-9 - _ . ~ ! ' ( ) * dışındaki her şeyi kodlar. Sorgu parametresi değerleri için encodeURIComponent() kullanın. encodeURI() yalnızca elinizde tam bir URL varsa ve yapısını bozmadan boşlukları veya ASCII dışı karakterleri düzeltmek istiyorsanız kullanın.
URL’lerde %20 neden bazen + olarak görünür?
Her ikisi de bir boşluğu temsil eder, ama farklı standartlardan gelirler. %20 RFC 3986 kuralını izler ve URL’nin her yerinde çalışır. + HTML form kodlama belirtimini izler ve yalnızca query string’lerde çalışır. Yol parçalarında + düz bir artı işaretidir. Tereddütteyseniz %20 kullanın.
Python, JavaScript, Go ve Java’da metni nasıl URL kodlarım?
JavaScript: encodeURIComponent('hello world') → hello%20world. Python: urllib.parse.quote('hello world') → hello%20world. Go: url.QueryEscape("hello world") → hello+world. Java: URLEncoder.encode("hello world", UTF_8) → hello+world. Go ve Java varsayılan olarak form kodlamasına geçer (boşluk = +); RFC 3986 çıktısı için + karakterini %20 ile değiştirin.
URL kodlaması güvenlik veya şifreleme için kullanılabilir mi?
Hayır. URL kodlaması anahtar gerektirmeden tamamen tersine çevrilebilir. Sıfır gizlilik sağlar. Hassas verileri yüzde kodlamasıyla değil, HTTPS ile koruyun. URL’ler sunucu kayıtlarında, tarayıcı geçmişinde ve Referer header’lerinde görünür; bu yüzden hassas veriler istek gövdelerinde yer almalıdır.
Çift kodlama nedir ve nasıl düzeltirim?
Çift kodlama, zaten kodlanmış bir karakter dizisi tekrar kodlandığında ortaya çıkar. %20 içindeki % %25 olarak kodlanır ve %2520 üretir. Sunucular bir boşluk yerine düz %20 metni görür. Bunu düzeltmek için önce girdiyi çözün, sonra bir kez kodlayın. İki onaltılık basamağın izlediği %25 deseni belirgin bir işarettir.
Azami URL uzunluğu nedir?
HTTP belirtiminde resmi bir azami yoktur. Geniş uyumluluk için güvenli sınır 2.000 karakterdir. Apache varsayılanı 8.190 bayt, Nginx ise 8.192 bayttır. ASCII dışı karakterler yüzde kodlandığında 3-12 kat genişler; bu yüzden uluslararasılaştırılmış URL’ler sınırlara daha hızlı ulaşır. Büyük yükler için POST’a geçin.