jQuery.parseJSON melempar kesalahan "JSON Tidak Valid" karena lolos dari penawaran tunggal di JSON


202

Saya membuat permintaan ke server saya menggunakan jQuery.post()dan server saya mengembalikan objek JSON (seperti { "var": "value", ... }). Namun, jika ada nilai yang berisi kutipan tunggal (seperti benar-benar lolos \'), jQuery gagal mengurai string JSON yang valid. Berikut ini contoh yang saya maksud ( dilakukan di konsol Chrome ):

data = "{ \"status\": \"success\", \"newHtml\": \"Hello \\\'x\" }";
eval("x = " + data); // { newHtml: "Hello 'x", status: "success" }

$.parseJSON(data); // Invalid JSON: { "status": "success", "newHtml": "Hello \'x" }

Apakah ini normal? Apakah tidak ada cara untuk melewati satu kutipan dengan benar melalui JSON?

Jawaban:


325

Menurut diagram mesin negara di situs web JSON , hanya karakter tanda kutip ganda yang lolos yang diizinkan, bukan tanda kutip tunggal. Karakter kutipan tunggal tidak perlu diloloskan:

http://www.json.org/string.gif


Perbarui - Informasi lebih lanjut untuk mereka yang tertarik:


Douglas Crockford tidak secara spesifik mengatakan mengapa spesifikasi JSON tidak memungkinkan tanda kutip tunggal yang lolos dalam string. Namun, selama diskusi tentang JSON dalam Lampiran E JavaScript: The Good Parts , ia menulis:

Tujuan desain JSON adalah minimal, portabel, tekstual, dan sebagian dari JavaScript. Semakin sedikit kita perlu menyetujui untuk beroperasi, semakin mudah kita dapat beroperasi.

Jadi mungkin dia memutuskan untuk hanya mengizinkan string didefinisikan menggunakan tanda kutip ganda karena ini adalah aturan yang kurang bahwa semua implementasi JSON harus setuju. Akibatnya, karakter kutipan tunggal dalam string tidak mungkin diakhiri secara tidak sengaja, karena menurut definisi string hanya dapat diakhiri oleh karakter tanda kutip ganda. Oleh karena itu tidak perlu untuk memungkinkan keluarnya karakter kutipan tunggal dalam spesifikasi formal.


Menggali sedikit lebih dalam, implementasi JSON untuk Java org.json Crockford lebih diizinkan dan memang memungkinkan karakter kutipan tunggal:

Teks-teks yang dihasilkan oleh metode toString benar-benar sesuai dengan aturan sintaks JSON. Konstruktor lebih memaafkan dalam teks yang akan mereka terima:

...

  • String dapat dikutip dengan '(kutipan tunggal).

Ini dikonfirmasi oleh kode sumber JSONTokener . The nextStringMetode menerima suatu lolos tunggal kutipan karakter dan memperlakukan mereka seperti karakter kutip ganda:

public String nextString(char quote) throws JSONException {
    char c;
    StringBuffer sb = new StringBuffer();
    for (;;) {
        c = next();
        switch (c) {

        ...

        case '\\':
            c = this.next();
            switch (c) {

            ...

            case '"':
            case '\'':
            case '\\':
            case '/':
                sb.append(c);
                break;
        ...

Di bagian atas metode adalah komentar informatif:

Format JSON formal tidak mengizinkan string dalam tanda kutip tunggal, tetapi implementasi diizinkan untuk menerimanya.

Jadi beberapa implementasi akan menerima tanda kutip tunggal - tetapi Anda tidak harus bergantung pada ini. Banyak implementasi populer sangat membatasi dalam hal ini dan akan menolak JSON yang berisi string kutip tunggal dan / atau lolos tanda kutip tunggal.


Akhirnya untuk mengikat ini kembali ke pertanyaan awal, jQuery.parseJSONupaya pertama untuk menggunakan parser JSON asli peramban atau pustaka yang dimuat seperti json2.js jika ada (yang pada catatan samping adalah pustaka yang menjadi dasar logika jQuery jika JSONtidak didefinisikan) . Dengan demikian jQuery hanya bisa seizin implementasi yang mendasarinya:

parseJSON: function( data ) {
    ...

    // Attempt to parse using the native JSON parser first
    if ( window.JSON && window.JSON.parse ) {
        return window.JSON.parse( data );
    }

    ...

    jQuery.error( "Invalid JSON: " + data );
},

Sejauh yang saya tahu implementasi ini hanya mematuhi spesifikasi JSON resmi dan tidak menerima tanda kutip tunggal, maka jQuery juga tidak.


4
UPDATE :: JQuery sangat membatasi ketika mengirimkan JSON. Jika Anda mencoba lansiran ($. ParseJSON ("[\" Ciao \\ '\ "]")); itu tidak berhasil karena apa yang dilaporkan Justin
daitangio

2
" Implementasi Crockford's org.json dari JSON untuk Java lebih diizinkan dan memang memungkinkan karakter kutipan tunggal " # Itu hanya praktik yang baik: prinsip ketahanan
Duncan Jones

1
@DuncanJones - Artikel ini mungkin memberikan wawasan tentang mengapa tidak ada peramban yang tampaknya mengikuti prinsip tersebut berkenaan dengan JSON: joelonsoftware.com/items/2008/03/17.html
Justin Ethier

1
@JustinEthier sebagaimana ditunjukkan oleh jawaban ini stackoverflow.com/a/25491642/759452 , JSON spec tools.ietf.org/html/rfc7159 mengatakan Any character may be escaped, ini dapat menjelaskan mengapa beberapa implementasi akan memungkinkan satu tanda kutip untuk diloloskan.
Adrien Be

1
@AdrienBe - Menarik ... tetapi apakah itu berarti ada karakter yang dapat lolos jika terdiri dari 4 digit hex? Menurut diagram keadaan di atas dan di bagian 7 dari RFC, lolos dari kutipan tunggal sebagaimana tertulis \'masih tidak diperbolehkan. Akan lebih baik jika RFC lebih eksplisit dalam hal ini.
Justin Ethier

15

Jika Anda memerlukan kutipan tunggal di dalam string, karena \ 'tidak ditentukan oleh spec, gunakan \u0027 lihat http://www.utf8-chartable.de/ untuk semuanya

edit: mohon alasan penyalahgunaan kata backticks di komentar. Maksud saya backslash. Maksud saya di sini adalah bahwa jika Anda memiliki string bersarang di dalam string lain, saya pikir itu bisa lebih berguna dan mudah dibaca untuk menggunakan unicode daripada banyak backslash untuk menghindari satu kutipan. Jika Anda tidak bersarang namun itu benar-benar lebih mudah untuk hanya menempatkan kutipan lama di sana.


29
Tidak. Cukup gunakan penawaran tunggal.
Jeff Kaufman

Kadang-kadang, itu lebih mudah untuk menggunakan unicode daripada ton back-ticks. Terutama ketika di dalam bolak-balik kutu.
slf

3
Mengapa Anda perlu backticks? Jika Anda memiliki string seperti "foo 'bar'" maka Anda tinggal membiarkan tanda kutip tunggal tidak terhapus.
Jeff Kaufman

3
persis apa yang saya cari. Saya mencoba untuk menulis string json ke halaman sebagai string js var dan melampirkannya dalam tanda kutip tunggal dan itu berakhir lebih awal setiap kali nilai properti memiliki tanda kutip tunggal di dalamnya. Sekarang saya hanya melakukan json.Replace ("'", "\ u0027") dalam kode di belakang sebelum menuliskannya ke halaman.
Zack

@ Zack Anda tidak harus menyertakan tanda kutip pada JSON. Jika Anda membutuhkan string dari string JSON yang ada, cukup rangkai lagi. di PHP, itu akan menjadi var jsonEncodedAsString = <?= json_encode(myEncodedJson) ?>tempat myEncodedJsondari hasil sebelumnya. json_encodeItu akan membantu lolos dari penawaran tunggal Anda, sebenarnya, itu hanya akan menghasilkan sesuatu string besar yang dibungkus dengan tanda kutip ganda, sehingga tanda kutip tunggal tidak akan lolos, tetapi tanda kutip ganda akan.
Juan Mendes

5

Saya mengerti di mana masalahnya terletak dan ketika saya melihat spesifikasi yang jelas bahwa tanda kutip tunggal yang tidak terhindar harus diurai dengan benar.

Saya menggunakan fungsi jQuery`s jQuery.parseJSON untuk mengurai string JSON tetapi masih mendapatkan kesalahan parse ketika ada kutipan tunggal dalam data yang disiapkan dengan json_encode.

Mungkinkah ini kesalahan dalam implementasi saya yang terlihat seperti ini (PHP - sisi server):

$data = array();

$elem = array();
$elem['name'] = 'Erik';
$elem['position'] = 'PHP Programmer';
$data[] = json_encode($elem);

$elem = array();
$elem['name'] = 'Carl';
$elem['position'] = 'C Programmer';
$data[] = json_encode($elem);

$jsonString = "[" . implode(", ", $data) . "]";

Langkah terakhir adalah saya menyimpan string yang dikodekan JSON ke dalam variabel JS:

<script type="text/javascript">
employees = jQuery.parseJSON('<?=$marker; ?>');
</script>

Jika saya menggunakan "" bukannya "masih ada kesalahan.

LARUTAN:

Satu-satunya hal yang berhasil bagi saya adalah menggunakan bitmask JSON_HEX_APOS untuk mengonversi kutipan tunggal seperti ini:

json_encode($tmp, JSON_HEX_APOS);

Apakah ada cara lain untuk mengatasi masalah ini? Apakah kode saya salah atau ditulis dengan buruk?

Terima kasih


'<? = $ marker; ?> 'ini bukan json yang valid. Kutipan di sekitarnya "dimakan" oleh penerjemah javascript, meninggalkan string yang dimulai dengan <... apa yang benar-benar ingin Anda coba adalah salah satu dari ini: jQuery.parseJSON ('"<? = $ Marker;?>" '); jQuery.parseJSON ("\" <? = $ marker;?> \ ""); Menurut spec, string json harus menggunakan tanda kutip ganda, tetapi javascript tidak peduli, jadi, Anda memiliki string javascript tanda kutip tunggal, atau tanda kutip ganda, tetapi jika Anda menggunakan yang terakhir, Anda harus melepaskan mereka dari semua penggunaan tanda kutip ganda di dalam string.
Chris Cogdon

3

Ketika Anda mengirim penawaran tunggal dalam permintaan

empid = " T'via"
empid =escape(empid)

Ketika Anda mendapatkan nilai termasuk penawaran tunggal

var xxx  = request.QueryString("empid")
xxx= unscape(xxx)

Jika Anda ingin mencari / memasukkan nilai yang mencakup satu kutipan dalam suatu kueri xxx=Replace(empid,"'","''")


1
Tetapi tidak perlu melarikan diri dari satu kutipan ketika melewati itu sebagai bagian dari string JSON ...
Justin Ethier

2

Menyerang masalah yang sama menggunakan CakePHP untuk menghasilkan blok skrip JavaScript menggunakan PHP asli json_encode. $contractorCompaniesberisi nilai-nilai yang memiliki tanda kutip tunggal dan seperti yang dijelaskan di atas dan diharapkan json_encode($contractorCompanies)tidak luput dari mereka karena JSON yang valid.

<?php $this->Html->scriptBlock("var contractorCompanies = jQuery.parseJSON( '".(json_encode($contractorCompanies)."' );"); ?>

Dengan menambahkan addlashes () di sekitar string JSON yang disandikan Anda kemudian luput dari tanda kutip yang memungkinkan Cake / PHP untuk menggemakan javascript yang benar ke browser. Kesalahan JS hilang.

<?php $this->Html->scriptBlock("var contractorCompanies = jQuery.parseJSON( '".addslashes(json_encode($contractorCompanies))."' );"); ?>

1

Saya mencoba untuk menyimpan objek JSON dari permintaan XHR ke dalam atribut data- HTML5 *. Saya mencoba banyak solusi di atas tanpa hasil.

Yang akhirnya saya lakukan adalah mengganti tanda kutip tunggal 'dengan kode &#39;menggunakan regex setelah metode stringify () memanggil dengan cara berikut:

var productToString = JSON.stringify(productObject);
var quoteReplaced = productToString.replace(/'/g, "&#39;");
var anchor = '<a data-product=\'' + quoteReplaced + '\' href=\'#\'>' + productObject.name + '</a>';
// Here you can use the "anchor" variable to update your DOM element.

0

Menarik. Bagaimana Anda menghasilkan JSON di ujung server? Apakah Anda menggunakan fungsi perpustakaan (sepertijson_encode dalam PHP), atau apakah Anda membuat string JSON dengan tangan?

Satu-satunya hal yang menarik perhatian saya adalah pelarian apostrof ( \'). Melihat bahwa Anda menggunakan tanda kutip ganda, seperti yang memang seharusnya, tidak perlu melarikan diri dari tanda kutip tunggal. Saya tidak dapat memeriksa apakah itu memang penyebab kesalahan jQuery Anda, karena saya sendiri belum memperbarui ke versi 1.4.1.


Saya menggunakan perpustakaan di PHP untuk menghasilkan objek JSON - agak ketinggalan untuk menuliskannya. Terima kasih telah menunjukkannya.
Erik Čerpnjak
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.