Skip to content
Bloga Dönün
Eğitimler

JSON dizelerini escape etme: karakterler, stringify ve tuzaklar

JSON'da bir dizeyi escape etme: hangi karakterlerin escape edilmesi gerektiği, JSON.stringify'dan farkı, JSON içinde JSON yuvalama, Unicode escape'leri ve yaygın tuzaklar.

9 dakika okuma

JSON Karakter Dizileri Nasıl Kaçışlanır: Karakterler, Stringify ve Tuzaklar

Bir JSON karakter dizisini kaçışlamak, rastgele metni bir JSON belgesinin içinde karakter dizisi değişmezi olarak güvenle durabilecek bir karakter dizisine dönüştürmek demektir. Birkaç karakter (çift tırnak, ters eğik çizgi ve satır sonu ile sekme gibi kontrol karakterleri) yapısal bir anlam taşır ya da bir JSON karakter dizisinin içinde basitçe yasa dışıdır; bu yüzden her biri \", \\ ya da \n gibi güvenli bir kaçış dizisiyle değiştirilir. Bunu yanlış yaparsanız payload’unuz ayrıştırılamaz hale gelir.

Bununla sürekli karşılaşırsınız: bir JSON nesnesini başka bir nesnenin içine karakter dizisi alanı olarak yuvalarken, çok satırlı bir kod parçacığını bir yapılandırma değerine yapıştırırken ya da curl için elle bir REST istek gövdesi kurarken. Bu rehber tam olarak hangi karakterlerin kaçışlanması gerektiğini ele alıyor, kaçışlama ile JSON.stringify arasındaki kafa karışıklığını gideriyor, JSON içinde JSON yuvalama ile Unicode kaçışlarını adım adım gösteriyor ve payload’ları sessizce bozan tuzakları sıralıyor. Hemen bir şeyi kaçışlamak istiyorsanız JSON Kaçış aracımız bunu tarayıcıda yapar, ama neden böyle çalıştığını merak ediyorsanız okumaya devam edin.

JSON Karakter Dizisi Kaçışlama Nedir?

JSON karakter dizisi kaçışlama, ham bir karakter dizisini bir JSON belgesinin içine gömülmesi güvenli bir biçime dönüştürmektir. JSON, yapısal anlam taşıyan küçük bir karakter kümesini ayırır: çift tırnak " bir karakter dizisini sınırlandırır ve ters eğik çizgi \ bir kaçış dizisini başlatır. Bunun yanında, U+0020’nin altındaki kontrol karakterleri (satır sonları, sekmeler, satır başları) bir JSON karakter dizisinin içinde düz olarak hiç görünemez. Kaçışlama bunların her birini güvenli bir diziyle değiştirir, böylece elde edilen karakter dizisi her yerde temiz biçimde ayrıştırılır.

Buna gerçekte ne zaman ihtiyaç duyarsınız? Birkaç durum tekrar tekrar karşımıza çıkar:

  • JSON içinde JSON: bir webhook zarfı, bir Kafka mesajı ya da bir denetim günlüğü, bir istek gövdesini karakter dizisi alanı olarak saklar; bu yüzden iç JSON, atanabilmeden önce kaçışlanmalıdır.
  • Elle yazılmış yapılandırma: çok satırlı bir kabuk betiğini, SQL sorgusunu ya da kod parçacığını tek bir JSON değerine yerleştirmek, her satır sonunu \n’e dönüştürmek demektir.
  • REST istek gövdeleri: curl ya da bir HTTP istemcisi için elle JSON gövdesi kurmak; burada tırnaklar ve satır sonları hem kabuktan hem de hattan sağ çıkmalıdır.
  • Günlüğe güvenli kodlama: kullanıcının sağladığı içeriği, araya sokulan bir tırnak ya da satır sonu biçimi bozmadan yapılandırılmış bir günlük satırına yazmak.

İşlem sırasıyla ilgili bir not. Dağınık ya da güvenilmeyen JSON’dan başlıyorsanız, iyi biçimlendirilmiş bir şeyi kaçışladığınızdan emin olmak için önce onu doğrulayın: düzgün biçimlendirip kontrol etmek için JSON Biçimlendirici aracına yapıştırın, sonra temiz sonucu kaçışlayın. Çöpü kaçışlarsanız size yalnızca kaçışlanmış çöp kalır.

JSON’da Hangi Karakterler Kaçışlanmalı

JSON belirtimi kesin ve kısa bir liste tanımlar. Yedi karakterin ayrılmış iki karakterlik bir kaçışı vardır ve U+0020’nin altındaki diğer her şey bir \uXXXX Unicode kaçışına düşer. İşte JSON kaçış karakterlerinin tam kümesi:

KarakterKaçışıNotlar
" (U+0022)\"Karakter dizisi sınırlayıcı
\ (U+005C)\\Kaçış başlatıcı (json kaçış ters eğik çizgi durumu)
satır sonu (U+000A)\n
satır başı (U+000D)\r
sekme (U+0009)\t
geri silme (U+0008)\b
sayfa ilerletme (U+000C)\f
U+0020 altı diğer kontroller\uXXXXörn. U+0000 → \u0000

Neyin kaçışlanması gerekmediği de en az o kadar önemlidir. İleri eğik çizgi / son derece normal bir karakterdir; onu kaçışlamak isteğe bağlıdır ve yalnızca aşağıda ele alınan dar bir durumda işe yarar. Tek tırnaklar asla kaçışlanmaya gerek duymaz, çünkü JSON onları sınırlayıcı olarak kullanmaz. U+0020’de ya da üzerindeki her yazdırılabilir karakter de olduğu gibi geçerlidir; buna é, ya da 😀 gibi tüm çok baytlı UTF-8 karakterleri dahildir.

Somut bir örnekte solda ham girdi, sağda kaçışlanmış JSON karakter dizisi değişmezi var:

Input:
She said "hello"	then left.

Escaped:
"She said \"hello\"\tthen left."

Çift tırnaklar \" oldu ve sekme \t oldu. Artık karakter dizisi herhangi bir JSON ayrıştırıcısına, günlük satırına ya da istek gövdesine bırakılacak kadar güvenlidir.

JSON Kaçış ve JSON Stringify: Fark Nedir?

Çoğu eğitim bu noktayı atlar ve bu yüzden pek çok kişinin kafası karışır. Kaçışlama ve JSON.stringify iki farklı işlem değil, aynı işlemin iki görünümüdür.

JSON.stringify(value) herhangi bir JavaScript değerini onun JSON metin gösterimine dönüştürür. O değer rastgele bir karakter dizisi olduğunda, dönüştürmek onu çift tırnağa sarmak ve içindeki özel karakterleri kaçışlamak demektir. Bu da tam olarak JSON kaçışlamadır. Yani JSON.stringify("a\tb"), tırnaklar dahil yedi karakterlik "a\tb" karakter dizisini döndürür.

Pratik soru, o dış tırnakları isteyip istemediğinizdir. Bu doğrudan JSON Kaçış aracındaki Çift tırnağa sar seçeneğine karşılık gelir:

Moda"b girdisi için çıktıNe zaman kullanılır
Sarma açık"a\"b"JSON.stringify ile özdeş, tam bir JSON karakter dizisi değişmezi. Onu bir değişkene atayın ya da iki nokta üst üsteden sonra yapıştırın.
Sarma kapalıa\"bYalnızca kaçışlanmış gövde, çevreleyen tırnaklar yok. Tırnakları bir JSON belgesinde kendiniz elle yazdığınızda kullanın.

Yani “json stringify” araması yapıp buraya geldiyseniz, zihinsel model basittir: bir karakter dizisini stringify etmek = sarma-açık kaçış. Tırnaksız biçim, dış tırnakları soyulmuş aynı şeydir.

Kodda JSON İçin Bir Karakter Dizisi Nasıl Kaçışlanır

Altın kural: asla bir replace() çağrıları zincirini elle yazmayın. Her ana akım dil, tırnakları, ters eğik çizgileri, kontrol karakterlerini ve Unicode’u doğru işleyen bir JSON dönüştürücüyle gelir. Onu kullanın.

JavaScript

const text = 'She said "hi"\nthen left.';
const escaped = JSON.stringify(text);
console.log(escaped);
// "She said \"hi\"\nthen left."

Bir karakter dizisi üzerinde JSON.stringify, size tam, tırnaklı değişmezi verir. Yalnızca gövdeyi mi istiyorsunuz? İlk ve son karakteri kesip atın: JSON.stringify(text).slice(1, -1).

Python

import json

text = 'She said "hi"\nthen left.'
print(json.dumps(text))
# "She said \"hi\"\nthen left."

print(json.dumps(text, ensure_ascii=False))
# "She said \"hi\"\nthen left."  (non-ASCII kept as UTF-8)

json.dumps, varsayılan olarak ensure_ascii=True kullanır; bu da her ASCII olmayan karakteri \uXXXX’e kaçışlar; bu da aracın ASCII’ye güvenli moduyla aynı davranıştır. Ham UTF-8’i korumak için ensure_ascii=False geçirin.

PHP

<?php
$text = "café \"quoted\"\nline";
echo json_encode($text);
// "caf\u00e9 \"quoted\"\nline"  (default escapes non-ASCII to \uXXXX)

echo json_encode($text, JSON_UNESCAPED_UNICODE);
// "café \"quoted\"\nline"

json_encode, varsayılan olarak hem ASCII olmayan karakterleri hem de ileri eğik çizgileri kaçışlar. Aksanları okunabilir tutmak için JSON_UNESCAPED_UNICODE, / karakterini olduğu gibi bırakmak için JSON_UNESCAPED_SLASHES ekleyin.

Go ve Java

Go’da json.Marshal(text), kaçışlanmış, tırnaklı baytları döndürür:

b, _ := json.Marshal(`a "quoted" line`)
// b == `"a \"quoted\" line"`

Java’da Jackson’ın objectMapper.writeValueAsString(text) ya da org.json’un JSONObject.quote(text) çağrısı aynı tırnaklı değişmezi üretir. Dil ne olursa olsun, kütüphaneye yaslanın; unutacağınız her sınır durumunu o zaten biliyor.

JSON İçine JSON Gömme (JSON içinde JSON)

İnsanların JSON’u elle kaçışlamasının en yaygın tek nedeni budur. Bir webhook zarfı, bir mesaj kuyruğu kaydı ya da bir denetim günlüğü çoğu zaman tüm bir istek gövdesini karakter dizisi alanı olarak saklar. Bunu yapmak için iç JSON’un önce kaçışlanması gerekir.

Küçük bir nesnenin iki katman kodlamadan geçişini izleyin:

1. Inner object:        {"a":1}
2. Escaped as a string: "{\"a\":1}"
3. Placed in envelope:  {"payload": "{\"a\":1}"}

İç nesnedeki her ", \" oldu ve bütün şey tek bir dış tırnak çiftine sarıldı. Sonuç, payload’a atayabileceğiniz tek bir geçerli karakter dizisi değeridir.

Daha derin yuvalamada işin püf noktası, ters eğik çizgilerin çoğalmasıdır. Halihazırda kaçışlanmış bir karakter dizisini kaçışlamak, onun ters eğik çizgilerini de kaçışlar; bu yüzden her katman onları kabaca ikiye katlar: \" olan bir iç tırnak, bir katman dışarıda \\\" olur ve bir katman daha dışarıda \\\\\" olur. Üç katman derin JSON içinde JSON’u okumak gerçekten zordur; bir aracın bu yüzden işe yaradığı yer burasıdır. Ters yöne gitmek ve iç nesneyi karakter dizisinden geri çekip çıkarmak için onu JSON Kaçış Çözme aracımızdan geçirin.

Unicode ve \uXXXX Kaçışlama

JSON, varsayılan olarak ham UTF-8’den memnundur. Bir é, é olarak kalır, bir , olarak kalır ve belge bu sayede daha okunabilir olur. Yazdırılabilir hiçbir Unicode karakterini kaçışlamanız gerekmez.

Peki ASCII’ye güvenli \uXXXX çıktısına ne zaman başvurursunuz? Yalnızca aşağı akış bir sistem UTF-8 ile güvenilemediğinde: eski SOAP ya da XML ağ geçitleri, belirli günlük hatları, e-posta başlıkları ya da saf ASCII kalması gereken kaynak dosyalar. ASCII’ye güvenli modda, U+007F üzerindeki her karakter bir \uXXXX kaçışı olur; café, caf\u00e9 haline gelir. Daha gürültülüdür ama bayt bayt ASCII’dir ve uyumlu herhangi bir ayrıştırıcıda geri orijinaline çözülür.

Bir incelik var. \uXXXX, tek bir 16 bitlik UTF-16 kod birimini kodlar, ama Temel Çok Dilli Düzlem’in dışındaki karakterler (emojiler, nadir betikler) 21 bite ihtiyaç duyar. JSON onları bir yedek çift ile işler: arka arkaya iki \uXXXX kaçışı. Sırıtan bir yüz 😀 (U+1F600), \ud83d\ude00 olur. Çoğu dönüştürücü bunu sizin için yapar; tehlike, yalnız ve eşleşmemiş bir yedek (surrogate) yayan elle yazılmış bir kaçışlayıcıdır.

Yedek çiftler ve kod noktaları sizin için yeni bir alansa, UTF-8 vs UTF-16 vs Unicode Kodlama Rehberi tek bir karakterin baytlara ve kod birimlerine tam olarak nasıl eşlendiğini ayrıntılı anlatır. Bir emojinin neden iki kaçışa ihtiyaç duyduğunun ardındaki eksik bağlamdır.

Kaçış Çözme: Kaçışlanmış JSON’u Geri Okumak

Kaçışlamanın bir tersi vardır. "a\tb" karakter dizisini gerçek iki satırlı ya da sekmeli metne geri çevirmek için onu ayrıştırırsınız: JavaScript’te JSON.parse(str), Python’da json.loads(str). Ayrıştırıcı her kaçış dizisini gezer ve yedek çiftler dahil orijinal karakterleri yeniden kurar.

Kaçış çözme başarısız olduğunda, hata neredeyse her zaman “geçersiz kaçış dizisi”dir ve birkaç olağan nedeni vardır:

  • JSON’un kaçış olarak tanımadığı bir karakterden önce gelen yalnız bir ters eğik çizgi, \q gibi.
  • \x41 gibi uydurma bir kaçış: JSON’un \x onaltılık kaçışı yoktur, yalnızca \u kullanır.
  • Dört onaltılık basamaktan az olan, kesik bir \u kaçışı, \u00 gibi.
  • Karakter dizisi sınırını bozan başıboş ya da dengesiz bir çift tırnak.

Her ters eğik çizginin geçerli kaçışlardan birini (\n \r \t \b \f \" \\ \/ \uXXXX) başlattığından ve tırnakların eşlendiğinden emin olun. Bir günlük satırının ortasından kopyalanmış (dış tırnakların geride kaldığı) kaçışlanmış karakter dizileri için, JSON Kaçış Çözme aracımız gövdeyi çevreleyen tırnaklarla ya da onlarsız kabul eder ve her iki şekilde de çözer.

Sık Yapılan JSON Kaçışlama Tuzakları

Bozuk payload’ların çoğu şu altı hatadan birine dayanır.

1. Çift kaçışlama. Halihazırda kaçışlanmış bir metni kaçışlamak \n’i \\n’e ve \"’yi \\\"’ye çevirir; böylece tüketici, satır sonu yerine düz bir ters eğik çizgi-n okur. Bu genelde bir yukarı akış servisi değeri zaten JSON kaçışlamışken sizin onu yeniden kaçışlamanızla olur. Mevcut durumu kontrol etmek için önce kaçışı çözün, sonra tam olarak bir kez kaçışlayın.

2. Dış tırnakları unutmak. Sarma kapalıyken yalnızca kaçışlanmış gövdeyi alırsınız, tam bir karakter dizisi değil. hello \"world\" ifadesini bir JSON değeri beklenen yere doğrudan yapıştırmak geçersizdir, çünkü çevreleyen tırnaklar eksiktir. Ya sarmayı açık tutun ya da tırnakları kendiniz yazın.

3. ASCII olmayanı aşırı kaçışlamak. Tüketici UTF-8’i sorunsuz işlerken ASCII’ye güvenli modu açmak çıktıyı yalnızca şişirir. café, hiçbir gerekçe olmadan caf\u00e9 olur; okuması daha zor, üstelik daha büyük ve karşılığında hiçbir fayda sağlamaz. Belirli bir eski sistem saf ASCII talep etmedikçe kapalı bırakın.

4. İleri eğik çizgiyi refleksle kaçışlamak. / kaçışı tam olarak tek bir yerde önemlidir: bir HTML &lt;script&gt; etiketinin içine satır içi yerleştirilmiş JSON; burada &lt;/script&gt; alt dizisi, JSON bağlamından bağımsız olarak etiketi erken kapatır. / karakterini \/’ye kaçışlamak onu etkisiz hale getirir. O tek durumun dışında, eğik çizgileri kaçışlamak saf dağınıklıktır; REST gövdeleri, yapılandırma dosyaları ve mesaj payload’ları için kapalı bırakın.

5. Elle yazılmış replace zincirleri. Elle bir replace('"', '\\"') hattı neredeyse her zaman bir şeyi unutur: bir kontrol karakteri, bir geri silme ya da bir yedek çift. Bütün belirtimi kapsayan dilin dönüştürücüsünü kullanın.

6. Kaçışlayıp asla kaçış çözmemek (ya da iki kez kaçış çözmek). Bir gidiş-dönüş dengeli olmalıdır. Girişte bir kez kaçışlayın, çıkışta bir kez kaçış çözün. İki kez kaçış çözerseniz verinin parçası olan gerçek ters eğik çizgileri bozarsınız.

Aklınızda tutmaya değer bir ayrım daha: JSON kaçışlama, URL ya da yüzde kodlama değildir. Farklı taşımalar için farklı sorunları çözerler ve onları karıştırmak (bir değeri yüzde kodlayıp sonra sonucu JSON kaçışlamak ya da tam tersi) hiçbir ayrıştırıcının temiz biçimde okuyamayacağı bir karmaşa üretir. URL Kodlama ve Çözme Rehberi, yüzde kodlamanın ne zaman doğru araç olduğunu ve JSON’un yaptığından nasıl farklılaştığını ele alır.

Sıkça Sorulan Sorular

JSON’da bir karakter dizisini kaçışlamak ne demektir?

JSON’a yapısal anlam taşıyan karakterleri (çift tırnak, ters eğik çizgi ve satır sonu ile sekme gibi kontrol karakterleri) \", \\ ve \n gibi güvenli kaçış dizileriyle değiştirmek demektir. Sonuç, ayrıştırmayı bozmadan bir JSON belgesinin içine karakter dizisi değişmezi olarak gömülebilir.

JSON’da hangi karakterler kaçışlanmalı?

Çift tırnak, ters eğik çizgi, satır sonu, satır başı, sekme, geri silme ve sayfa ilerletme her biri ayrılmış bir kaçış alır ve U+0020’nin altındaki diğer her kontrol karakteri \uXXXX olur. Yazdırılabilir karakterler ve çok baytlı UTF-8 hiçbir kaçışlamaya gerek duymaz; ileri eğik çizgi isteğe bağlıdır ve yalnızca HTML &lt;script&gt; etiketlerinin içinde önemlidir.

JSON kaçış, JSON.stringify ile aynı mıdır?

Çoğunlukla tek bir işlemin iki görünümü. Bir karakter dizisine uygulanan JSON.stringify onu çift tırnağa sarar ve içindeki özel karakterleri kaçışlar; işte bu JSON kaçışlamadır. Sarma açık, tırnaklı biçime eşittir (JSON.stringify ile özdeş); sarma kapalı, size çevreleyen tırnaklar olmadan yalnızca kaçışlanmış gövdeyi verir.

JavaScript ya da Python’da bir karakter dizisini JSON için nasıl kaçışlarım?

JavaScript’te JSON.stringify(str), Python’da json.dumps(str) kullanın. Elle yazılmış bir replace zinciri yerine her zaman yerleşik işleve yaslanın; yerleşik işlevler Unicode’u, kontrol karakterlerini ve aksi takdirde kaçıracağınız her sınır durumunu doğru işler.

JSON’um neden fazladan ters eğik çizgilerle bozuluyor?

Olağan neden çift kaçışlamadır: halihazırda kaçışlanmış bir metni kaçışlamak, böylece \n, \\n olur ve tüketici satır sonu yerine düz bir ters eğik çizgi-n okur. Değerin gerçek durumunu kontrol etmek için önce kaçışını çözün, sonra onu tam olarak bir kez kaçışlayın.

JSON’da ileri eğik çizgileri ya da Unicode’u kaçışlamam gerekir mi?

Hiçbiri gerekli değildir. / normal bir karakterdir ve yalnızca JSON’u bir HTML &lt;script&gt; etiketinin içine satır içi yerleştirdiğinizde, &lt;/script&gt; dizisinin onu erken kapatmasını durdurmak için kaçışlanması gerekir. Unicode varsayılan olarak ham UTF-8 olarak kalır; \uXXXX’i yalnızca aşağı akış bir sistem UTF-8’i işleyemediğinde kullanın.

Etiketler: JSON Encoding Data Formats JavaScript