Bagaimana cara menguji apakah suatu string adalah JSON atau tidak?

191

Saya punya panggilan AJAX sederhana, dan server akan mengembalikan string JSON dengan data yang berguna atau string pesan kesalahan yang dihasilkan oleh fungsi PHP mysql_error(). Bagaimana saya bisa menguji apakah data ini adalah string JSON atau pesan kesalahan.

Akan menyenangkan untuk menggunakan fungsi yang disebut isJSONsama seperti Anda dapat menggunakan fungsi instanceofuntuk menguji apakah ada sesuatu yang merupakan Array.

Ini yang aku inginkan:

if (isJSON(data)){
    //do some data stuff
}else{
    //report the error
    alert(data);
}
jeffery_the_wind
sumber
Mungkin menggunakan eval()jika itu kembali undefinedmaka, itu bukan JSON
MatuDuke
4
Ini telah dipecahkan di sini: stackoverflow.com/questions/3710204/…
Reinard
2
Terima kasih semuanya, maaf saya tidak menemukan posting lain sebelumnya.
jeffery_the_wind
1
Secara teknis ini bukan duplikat dari 3710.204 karena yang bertanya apakah itu sah json yang merupakan bar yang jauh lebih tinggi untuk lulus daripada json sama sekali.
carlin.scott
Kemungkinan duplikat AJAX: Periksa apakah string adalah JSON?
Mehdi Dehghani

Jawaban:

324

Gunakan JSON.parse

function isJson(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
}
Maksud
sumber
53
Penanganan pengecualian seharusnya tidak digunakan untuk melakukan sesuatu yang diharapkan.
luisZavaleta
46
JSON.parse(1234)ATAU JSON.parse(0)ATAU JSON.parse(false)ATAU JSON.parse(null)semua tidak akan meningkatkan Pengecualian dan akan kembali benar !!. jangan gunakan jawaban ini
Zalaboza
19
@Zalaboza 1234, 0, false, dan nullsemua nilai-nilai JSON valid. Jika Anda ingin predikat yang menguji jika JSON mewakili objek, Anda harus melakukan sedikit lagi.
Michael Lang
20
JSON.parsemelakukan banyak perhitungan untuk mengurai string, dan memberi Anda objek json jika berhasil, namun Anda membuang hasil yang mungkin ingin digunakan beberapa pengguna. Itu sepertinya tidak baik. Sebaliknya saya return {value: JSON.parse(str), valid: true};dan di blok tangkap return {value: str, valid: false};.. dan saya akan mengubah nama fungsi menjadi tryParse().
Nawaz
7
@luisZavaleta lalu apa yang Anda sarankan sebagai metode
PirateApp
80

Kode ini JSON.parse(1234)atau JSON.parse(0)atau JSON.parse(false)atau JSON.parse(null)semuanya akan kembali benar.

function isJson(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
}

Jadi saya menulis ulang kode dengan cara ini:

function isJson(item) {
    item = typeof item !== "string"
        ? JSON.stringify(item)
        : item;

    try {
        item = JSON.parse(item);
    } catch (e) {
        return false;
    }

    if (typeof item === "object" && item !== null) {
        return true;
    }

    return false;
}

Hasil pengujian:

isJson hasil tes

kubosho_
sumber
4
Kerja bagus! Pernyataan terakhir Anda jika dapat disederhanakan menjadi pernyataan pengembalian sederhana seperti:return (typeof suspect === "object" && suspect !== null);
Nebulosar
39

Mari kita rekap ini (untuk 2019+).

Argumen : Nilai-nilai seperti true, false, nullberlaku JSON (?)

FAKTA : Nilai-nilai primitif ini adalah JSON-parsable tetapi mereka bukan struktur JSON yang terbentuk dengan baik. Spesifikasi JSON menunjukkan JSON dibangun di atas dua struktur: Kumpulan pasangan nama / nilai (objek) atau daftar nilai yang terurut (array).

Argumen : Penanganan pengecualian tidak boleh digunakan untuk melakukan sesuatu yang diharapkan.
(Ini adalah komentar yang memiliki 25+ upvotes!)

FAKTA : Tidak! Sudah pasti legal untuk menggunakan try / catch, terutama dalam kasus seperti ini. Jika tidak, Anda harus melakukan banyak hal analisis string seperti operasi tokenizing / regex; yang akan memiliki kinerja yang buruk.

hasJsonStructure()

Ini berguna jika tujuan Anda adalah untuk memeriksa apakah beberapa data / teks memiliki format pertukaran JSON yang tepat.

function hasJsonStructure(str) {
    if (typeof str !== 'string') return false;
    try {
        const result = JSON.parse(str);
        const type = Object.prototype.toString.call(result);
        return type === '[object Object]' 
            || type === '[object Array]';
    } catch (err) {
        return false;
    }
}

Pemakaian:

hasJsonStructure('true')             // —» false
hasJsonStructure('{"x":true}')       // —» true
hasJsonStructure('[1, false, null]') // —» true

safeJsonParse()

Dan ini berguna jika Anda ingin berhati-hati saat mengurai beberapa data ke nilai JavaScript.

function safeJsonParse(str) {
    try {
        return [null, JSON.parse(str)];
    } catch (err) {
        return [err];
    }
}

Pemakaian:

const [err, result] = safeJsonParse('[Invalid JSON}');
if (err) {
    console.log('Failed to parse JSON: ' + err.message);
} else {
    console.log(result);
}
Onur Yıldırım
sumber
1
Anda menautkan ke JSON Spec mengatakan yang berikut: "Teks JSON adalah urutan token yang dibentuk dari titik kode Unicode yang sesuai dengan tata bahasa nilai JSON." dan "Nilai JSON dapat berupa objek, array, angka, string, true, false, atau null." - Bagaimana Anda sampai pada kesimpulan bahwa JSON hanya bisa menjadi objek atau array di tingkat root? Saya tidak bisa melihat ini di spec, atau apa pun tentang "struktur JSON yang terbentuk dengan baik"
Relequestual
Baca paragraf kedua yang dimulai dengan "JSON dibangun di atas dua struktur ..." @ json.org atau paragraf ke-4 dan ke-5 dari ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
Onur Yıldırım
json.org hanya bersifat informatif. Membaca spesifikasi yang ditautkan tidak mendukung saran Anda. Spesifikasi menyebutkan RFC 8259 sebagai RFC terbaru. Lihatlah contoh-contoh JSON tex yang valid yang hanya berisi nilai tools.ietf.org/html/rfc8259#section-13 - RFC 8259 dirancang untuk menyelesaikan kemungkinan ambiguitas dan kebingungan, seperti ini.
Relequestual
Baca jawabannya lagi. Saya mengatakan nilai seperti primitif (yaitu nilai teks dalam contoh RFC) bukan "struktur" JSON. Tidak ada ambiguitas. Anda BISA menguraikannya sebagai JSON, itu sah untuk melakukannya. Tetapi mereka bukan data terstruktur. JSON terutama ditemukan sebagai format interchange »yang digunakan untuk data terstruktur» yang dapat berupa objek atau array.
Onur Yıldırım
1
OK, jadi saya pikir kami setuju. Primatif adalah JSON yang valid sesuai dengan spesifikasi, tetapi bukan "struktur". Tidak apa-apa. Tapi, Anda berkata "Argumen: Nilai-nilai seperti true, false, null adalah JSON (?) Yang valid. Fakta: Ya dan tidak!" - Faktanya adalah JSON yang valid sesuai dengan spesifikasi. Pendapat tentang apakah itu berguna atau tidak, tidak relevan dengan fakta itu.
Relequestual
20

Jika server merespons dengan JSON maka ia akan memiliki tipe application/jsonkonten, jika merespons dengan pesan teks biasa maka ia harus memiliki tipe text/plainkonten. Pastikan server merespons dengan tipe konten yang benar dan mengujinya.

Quentin
sumber
4
Ini salah, ada banyak jenis lain yang kompatibel dengan json. Selanjutnya overrideMimeTypedapat menimpa header tipe konten.
Knu
14

saat menggunakan jQuery $.ajax()respons akan memiliki responseJSONproperti jika responsnya adalah JSON, ini dapat diperiksa seperti ini:

if (xhr.hasOwnProperty('responseJSON')) {}
Remy
sumber
3
Ini saya kira benar-benar jawaban yang kebanyakan orang cari, mungkin bahkan OP
Kirby
1
Ini jauh lebih elegan daripada menggunakan blok try catch
Anurag Sinha
6

Saya suka jawaban terbaik tetapi jika itu adalah string kosong mengembalikan benar. Jadi inilah perbaikannya:

function isJSON(MyTestStr){
    try {
        var MyJSON = JSON.stringify(MyTestStr);
        var json = JSON.parse(MyJSON);
        if(typeof(MyTestStr) == 'string')
            if(MyTestStr.length == 0)
                return false;
    }
    catch(e){
        return false;
    }
    return true;
}
Lonnie Price Sr.
sumber
var json tidak digunakan? atau hanya untuk menangkap kesalahan?
stackdave
5
var parsedData;

try {
    parsedData = JSON.parse(data)
} catch (e) {
    // is not a valid JSON string
}

Namun, saya akan menyarankan kepada Anda bahwa panggilan / layanan http Anda harus selalu mengembalikan data dalam format yang sama. Jadi jika Anda memiliki kesalahan, maka Anda harus memiliki objek JSON yang membungkus kesalahan ini:

{"error" : { "code" : 123, "message" : "Foo not supported" } } 

Dan mungkin menggunakan status HTTP serta kode 5xx.

ZER0
sumber
5

Yah ... Itu tergantung cara Anda menerima data Anda. Saya pikir server merespons dengan string yang diformat JSON (menggunakan json_encode () dalam PHP, misalnya). Jika Anda menggunakan posting JQuery dan mengatur data respons menjadi format JSON dan itu adalah JSON yang salah bentuk, ini akan menghasilkan kesalahan:

$.ajax({
  type: 'POST',
  url: 'test2.php',
  data: "data",
  success: function (response){

        //Supposing x is a JSON property...
        alert(response.x);

  },
  dataType: 'json',
  //Invalid JSON
  error: function (){ alert("error!"); }
});

Tetapi, jika Anda menggunakan respons tipe sebagai teks, Anda perlu menggunakan $ .parseJSON. Menurut situs jquery: "Melewati string JSON yang salah dapat menghasilkan pengecualian yang dilemparkan". Dengan demikian kode Anda akan:

$.ajax({
  type: 'POST',
  url: 'test2.php',
  data: "data",
  success: function (response){

        try {
            parsedData = JSON.parse(response);
        } catch (e) {
            // is not a valid JSON string
        }

  },
  dataType: 'text',
});
Lucas Batistussi
sumber
kecuali, tentu saja Anda mencoba untuk menguraikan teks kesalahan dalam fungsi kesalahan dalam contoh di atas dan tidak yakin apakah itu JSON ...
Kirby
Jawaban yang bagus, meskipun jika responsekosong, ia akan menuju ke success: '(
Henrik Petterson
4

Mungkin ada tes yang dapat Anda lakukan, misalnya jika Anda tahu bahwa JSON yang dikembalikan selalu akan dikelilingi oleh {dan }kemudian Anda dapat menguji untuk karakter-karakter itu, atau metode peretasan lainnya. Atau Anda bisa menggunakan pustaka JS json.org untuk mencoba dan menguraikannya dan mengujinya jika berhasil.

Namun saya akan menyarankan pendekatan yang berbeda. Skrip PHP Anda saat ini mengembalikan JSON jika panggilan berhasil, tetapi ada yang lain jika tidak. Mengapa tidak selalu mengembalikan JSON?

Misalnya

Panggilan sukses:

{ "status": "success", "data": [ <your data here> ] }

Panggilan salah:

{ "status": "error", "error": "Database not found" }

Ini akan membuat menulis sisi klien Anda JS jauh lebih mudah - yang harus Anda lakukan adalah memeriksa "status" anggota dan bertindak sesuai.

mdm
sumber
4

Saya hanya menggunakan 2 baris untuk melakukan itu:

var isValidJSON = true;
try { JSON.parse(jsonString) } catch { isValidJSON = false }

Itu saja!

Namun perlu diingat ada 2 jebakan:
1. JSON.parse(null)return null
2. Semua angka atau string dapat diuraikan dengan JSON.parse()metode.
   JSON.parse("5")mengembalikan 5
   JSON.parse(5)pengembalian5

Mari kita bermain kode:

// TEST 1
var data = '{ "a": 1 }'

// Avoiding 'null' trap! Null is confirmed as JSON.
var isValidJSON = data ? true : false
try { JSON.parse(data) } catch(e) { isValidJSON = false }

console.log("data isValidJSON: ", isValidJSON);
console.log("data isJSONArray: ", isValidJSON && JSON.parse(data).length ? true : false);

Console outputs:
data isValidJSON:  true
data isJSONArray:  false


// TEST 2
var data2 = '[{ "b": 2 }]'

var isValidJSON = data ? true : false
try { JSON.parse(data2) } catch(e) { isValidJSON = false }

console.log("data2 isValidJSON: ", isValidJSON);
console.log("data2 isJSONArray: ", isValidJSON && JSON.parse(data2).length ? true : false);

Console outputs:
data2 isValidJSON:  true
data2 isJSONArray:  true


// TEST 3
var data3 = '[{ 2 }]'

var isValidJSON = data ? true : false
try { JSON.parse(data3) } catch(e) { isValidJSON = false }

console.log("data3 isValidJSON: ", isValidJSON);
console.log("data3 isJSONArray: ", isValidJSON && JSON.parse(data3).length ? true : false);

Console outputs:
data3 isValidJSON:  false
data3 isJSONArray:  false


// TEST 4
var data4 = '2'

var isValidJSON = data ? true : false
try { JSON.parse(data4) } catch(e) { isValidJSON = false }

console.log("data4 isValidJSON: ", isValidJSON);
console.log("data4 isJSONArray: ", isValidJSON && JSON.parse(data4).length ? true : false);


Console outputs:
data4 isValidJSON:  true
data4 isJSONArray:  false


// TEST 5
var data5 = ''

var isValidJSON = data ? true : false
try { JSON.parse(data5) } catch(e) { isValidJSON = false }

console.log("data5 isValidJSON: ", isValidJSON);
console.log("data5 isJSONArray: ", isValidJSON && JSON.parse(data5).length ? true : false);


Console outputs:
data5 isValidJSON:  false
data5 isJSONArray:  false

// TEST 6
var data6; // undefined

var isValidJSON = data ? true : false
try { JSON.parse(data6) } catch(e) { isValidJSON = false }

console.log("data6 isValidJSON: ", isValidJSON);
console.log("data6 isJSONArray: ", isValidJSON && JSON.parse(data6).length ? true : false);

Console outputs:
data6 isValidJSON:  false
data6 isJSONArray:  false
efkan
sumber
Saya telah membuat biola untuk jawaban ini di jsfiddle.net/fatmonk/gpn4eyav yang mencakup opsi untuk menambahkan data uji pengguna Anda sendiri juga. Ini terlihat seperti dasar dari fungsi perpustakaan yang baik bagi saya, tetapi saya ingin lebih memahami mengapa Test 1 bukan array JSON yang valid.
Fat Monk
Karena array harus ditentukan dengan menggunakan [dan ]. Misalnya, [1, 2, 3]adalah array angka. ["a", "b", "c"]adalah array string. Dan [{"a":1}, {"b":2}]merupakan array JSON. Pekerjaan jsfiddle Anda tampaknya sangat berguna!
efkan
Sesimpel itu?! Jadi Test 1 adalah objek JSON dan Test 2 adalah array JSON yang terdiri dari elemen objek JSON tunggal. Sudahkah saya memahaminya dengan benar?
Fat Monk
Pertanyaan yang ditandai sebagai kemungkinan duplikat dari ini ( stackoverflow.com/questions/3710204/… ) bertanya tentang mencapai ini tanpa menggunakan try / catch, jadi saya sudah bercabang-cabang untuk mencoba mencapai tujuan itu juga. Garpu ada di jsfiddle.net/fatmonk/827jsuvr dan bekerja dengan semua tes di atas kecuali untuk Tes 3 yang kesalahannya di JSON.parse. Adakah yang bisa menyarankan cara menghindari kesalahan itu tanpa menggunakan coba?
Fat Monk
jsfiddleAplikasi Anda melempar kesalahan karena Tes 3 tidak memiliki ekspresi JSON yang valid. Jadi a try-catchharus digunakan untuk menangkap kesalahan itu dan untuk mengevaluasi kesalahan karena ekspresi bukan JSON ketika parsing seperti Test 3 di atas:try { JSON.parse(data3) } catch(e) { isValidJSON = false }
efkan
2

Anda dapat mencoba mendekodekannya dan menangkap pengecualian (asli atau json2.js ):

try {
  newObj = JSON.parse(myJsonString);
} catch (e) {
  console.log('Not JSON');
}

Namun, saya menyarankan agar respons JSON selalu valid. Jika Anda mendapatkan kesalahan kembali dari permintaan MySQL Anda, cukup kirim kembali JSON dengan kesalahan:

{"error":"The MySQL error string."}

Lalu:

if (myParsedJSON.error) {
  console.log('An error occurred: ' + myParsedJSON.error);
}
James Sumners
sumber
2

Peringatan: Untuk metode yang mengandalkan JSON.parse- Array dan kutipan string yang dikelilingi akan berlalu juga (mis. console.log(JSON.parse('[3]'), JSON.parse('"\uD800"')))

Untuk menghindari semua primitif JSON non-objek (boolean, null, array, number, string), saya sarankan menggunakan yang berikut ini:

/* Validate a possible object ie. o = { "a": 2 } */
const isJSONObject = (o) => 
  !!o && (typeof o === 'object') && !Array.isArray(o) && 
  (() => { try { return Boolean(JSON.stringify(o)); } catch { return false } })()

/* Validate a possible JSON object represented as string ie. s = '{ "a": 3 }' */
function isJSONObjectString(s) {
    try {
        const o = JSON.parse(s);
        return !!o && (typeof o === 'object') && !Array.isArray(o)
    } catch {
        return false
    }
}

Penjelasan Kode

  • !! o - Tidak palsu (tidak termasuk null, yang mendaftar sebagai jenis 'objek')
  • (typeof o === 'objek') - Tidak termasuk boolean, angka, dan string
  • ! Array.isArray (o) - Kecualikan array (yang mendaftar sebagai jenis 'objek')
  • coba ... JSON.stringify / JSON.parse - Minta mesin JavaScript untuk menentukan apakah JSON valid

Mengapa tidak menggunakan jawaban hasJsonStructure ()?

Mengandalkan toString()bukan ide yang bagus. Ini karena Mesin JavaScript yang berbeda dapat mengembalikan representasi string yang berbeda. Secara umum, metode yang mengandalkan ini dapat gagal di lingkungan yang berbeda atau dapat mengalami kegagalan nanti jika mesin mengubah hasil string

Mengapa menangkap pengecualian bukan peretasan?

Dikatakan bahwa menangkap pengecualian untuk menentukan validitas sesuatu tidak pernah merupakan cara yang tepat untuk dilakukan. Ini umumnya nasihat yang baik, tetapi tidak selalu. Dalam hal ini, penangkapan pengecualian kemungkinan adalah rute terbaik karena bergantung pada implementasi mesin JavaScript dalam memvalidasi data JSON.

Mengandalkan mesin JS menawarkan keuntungan berikut:

  1. Lebih teliti dan terus diperbarui seiring dengan perubahan spesifikasi JSON
  2. Kemungkinan untuk berjalan lebih cepat (karena ini kode level lebih rendah)

Ketika diberi kesempatan untuk bersandar pada mesin JavaScript, saya sarankan melakukannya. Khususnya dalam hal ini. Meskipun mungkin terasa gila untuk menangkap pengecualian, Anda benar-benar hanya menangani dua status pengembalian yang mungkin dari metode eksternal.

Ron S.
sumber
1

Ini adalah kode dengan sedikit modifikasi dalam jawaban Bourne. Karena JSON.parse (angka) berfungsi dengan baik tanpa kecuali sehingga ditambahkan isNaN.

function isJson(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return isNaN(str);
}
Devashish Mamgain
sumber
0

Semua string json dimulai dengan '{' atau '[' dan diakhiri dengan '}' atau '] yang sesuai, jadi cukup periksa untuk itu.

Begini cara Angular.js melakukannya:

var JSON_START = /^\[|^\{(?!\{)/;
var JSON_ENDS = {
  '[': /]$/,
  '{': /}$/
};

function isJsonLike(str) {
    var jsonStart = str.match(JSON_START);
    return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
}

https://github.com/angular/angular.js/blob/v1.6.x/src/ng/http.js

carlin.scott
sumber
@DukeDougal peduli untuk menjelaskan? Kadang-kadang orang memulai json mereka dengan '[' tetapi itu tidak terlalu umum.
carlin.scott
1
Anda perlu menguraikannya agar berhasil. JSON itu valid. Jika JSON tidak valid maka bukan JSON. Pertanyaannya adalah "bagaimana cara mengetahui apakah sebuah string adalah JSON atau tidak?". Dengan pendekatan Anda, ini akan menjadi JSON {fibble - dan itu benar-benar bukan JSON. Pertimbangkan juga kasus seperti nomor 1 sendiri - yaitu JSON yang valid.
Duke Dougal

1
"Jika JSON tidak valid maka bukan JSON". Fakta bahwa Anda harus menggunakan kata "valid" menunjukkan bahwa Anda menambahkan kualifikasi pada fakta bahwa itu lebih dari sekadar json. Pertanyaannya hanyalah "apakah itu json" dan contoh kode saya menjawab pertanyaan itu dengan sempurna tanpa mengasumsikan persyaratan tambahan.
carlin.scott

ide buruk jika Anda menggunakan beberapa sistem template dan Anda memiliki sesuatu seperti { someValue }akan secara otomatis melewati validasi.
ncubica

@ncubica sehingga Anda menggunakan templat untuk selain json, string hanya berisi placeholder yang menggunakan kurung kurawal, dan mesin templat gagal mengganti placeholder dengan nilai sebenarnya? Juga perlu diingat, seperti yang sudah saya jelaskan kepada Duke, pertanyaan awal tidak menyebutkan validasi. Mereka hanya ingin tahu apakah itu terlihat seperti json atau tidak.
carlin.scott

0

Saya sarankan dalam mode skrip:

export function stringify(data: any): string {
    try {
         return JSON.stringify(data)
    } catch (e) {
         return 'NOT_STRINGIFIABLE!'
    }
}

0

Saya menggunakan yang ini (semacam campuran jawaban yang berbeda, tapi tetap saja):

const isJSON = str => {
  if (typeof str === 'string'){
    try {
      JSON.parse(str)
      return true
    } catch(e){
    }
  }
  return false
}



[null, undefined, false, true, [], {}, 
 '', 'asdf', '{}', '[]', "{\"abc\": 2}","{\"abc\": \"2\"}"]
  .map(el => {
      console.log(`[>${el}<] - ${isJSON(el)}`)
})

console.log('-----------------')


0

Anda dapat mencoba yang berikut karena ini juga memvalidasi angka, null, string tetapi jawaban yang ditandai di atas tidak berfungsi dengan benar itu hanya perbaikan dari fungsi di atas:

function isJson(str) {
  try {
      const obj = JSON.parse(str);
      if (obj && typeof obj === `object`) {
        return true;
      }
    } catch (err) {
      return false;
    }
   return false;
}

-1

Selain jawaban sebelumnya, jika Anda perlu memvalidasi format JSON seperti "{}", Anda dapat menggunakan kode berikut:

const validateJSON = (str) => {
  try {
    const json = JSON.parse(str);
    if (Object.prototype.toString.call(json).slice(8,-1) !== 'Object') {
      return false;
    }
  } catch (e) {
    return false;
  }
  return true;
}

Contoh penggunaan:

validateJSON('{}')
true
validateJSON('[]')
false
validateJSON('')
false
validateJSON('2134')
false
validateJSON('{ "Id": 1, "Name": "Coke" }')
true
K. Raja