Come verificare se una stringa è JSON o no?


191

Ho una semplice chiamata AJAX e il server restituirà una stringa JSON con dati utili o una stringa di messaggio di errore prodotta dalla funzione PHP mysql_error(). Come posso verificare se questi dati sono una stringa JSON o il messaggio di errore.

Sarebbe bello usare una funzione chiamata isJSONproprio come è possibile utilizzare la funzione instanceofper verificare se qualcosa è un array.

Questo è quello che voglio:

if (isJSON(data)){
    //do some data stuff
}else{
    //report the error
    alert(data);
}

Forse usando eval()se ritorna undefinedallora, non è JSON
MatuDuke il

4
Questo è stato risolto qui: stackoverflow.com/questions/3710204/…
Reinard

2
Grazie a tutti, scusate se non ho trovato quell'altro post prima.
jeffery_the_wind

1
Tecnicamente questo non è un duplicato di 3710204 poiché si chiede se è json valido che è una barra molto più alta da passare di quanto non sia affatto json.
carlin.scott,

Risposte:


324

Usa JSON.parse

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

53
La gestione delle eccezioni non deve essere utilizzata per fare qualcosa di previsto.
luisZavaleta,

46
JSON.parse(1234)O JSON.parse(0)O JSON.parse(false)O JSON.parse(null)tutto non fa salire Exception e restituirà true !!. non usare questa risposta
Zalaboza,

19
@Zalaboza 1234, 0, false, e nullsono tutti valori JSON validi. Se si desidera un predicato che verifica se JSON rappresenta un oggetto, è necessario fare un po 'di più.
Michael Lang,

20
JSON.parsefa un sacco di calcoli per analizzare la stringa e darti l'oggetto json se riesce, ma stai scartando il risultato che alcuni utenti potrebbero voler usare. Non sembra essere buono. Avrei invece return {value: JSON.parse(str), valid: true};e nel blocco catch return {value: str, valid: false};.. e avrei cambiato il nome della funzione in tryParse().
Nawaz,

7
@luisZavaleta quindi cosa suggerisci come metodo
PirateApp il

80

Questo codice è JSON.parse(1234)o JSON.parse(0)o JSON.parse(false)o JSON.parse(null)tutto restituirà vero.

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

Quindi riscrivo il codice in questo modo:

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;
}

Risultato del test:

risultato del test isJson


4
Bel lavoro! La tua ultima dichiarazione if potrebbe essere semplificata in una semplice dichiarazione di ritorno come:return (typeof suspect === "object" && suspect !== null);
Nebulosar,

39

Ricapitoliamo questo (per il 2019+).

Argomento : Valori come true, false, nullsono validi JSON (?)

FATTO : questi valori primitivi sono analizzabili JSON ma non sono strutture JSON ben formate . La specifica JSON indica che JSON è basato su due strutture: una raccolta di coppie nome / valore (oggetto) o un elenco ordinato di valori (matrice).

Argomento : la gestione delle eccezioni non deve essere utilizzata per fare qualcosa di previsto.
(Questo è un commento che ha più di 25 voti!)

FATTO : No! È assolutamente legale usare try / catch, specialmente in un caso come questo. Altrimenti, avresti bisogno di fare molte cose di analisi delle stringhe come le operazioni di tokenizzazione / regex; che avrebbe prestazioni terribili.

hasJsonStructure()

Ciò è utile se il tuo obiettivo è verificare se alcuni dati / testo hanno un formato di interscambio JSON adeguato.

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;
    }
}

Uso:

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

safeJsonParse()

E questo è utile se vuoi stare attento quando analizzi alcuni dati su un valore JavaScript.

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

Uso:

const [err, result] = safeJsonParse('[Invalid JSON}');
if (err) {
    console.log('Failed to parse JSON: ' + err.message);
} else {
    console.log(result);
}

1
Il collegamento alle specifiche JSON indica quanto segue: "Un testo JSON è una sequenza di token formata da punti di codice Unicode che è conforme alla grammatica del valore JSON". e "Un valore JSON può essere un oggetto, un array, un numero, una stringa, vero, falso o nullo." - Come sei arrivato alla conclusione che un JSON può essere solo oggetto o array a livello di root? Non riesco a vedere questo nelle specifiche, né nulla riguardo alle "strutture JSON ben formate"
Relequestual

Leggi il secondo paragrafo che inizia con "JSON è costruito su due strutture ..." @ json.org o 4 ° e 5 ° paragrafo di ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
Onur Yıldırım

json.org è solo informativo. La lettura delle specifiche a cui ti sei collegato non supporta il tuo suggerimento. Le specifiche menzionano RFC 8259 come l'ultimo RFC. Dai un'occhiata agli esempi di tex JSON validi che contengono solo valori tools.ietf.org/html/rfc8259#section-13 - RFC 8259 è progettato per risolvere possibili ambiguità e confusioni, proprio in questo modo.
Relequestual

Leggi di nuovo la risposta. Sto dicendo che valori come le primitive (ovvero i valori di testo negli esempi RFC) non sono "strutture" JSON. Non ci sono ambiguità. È possibile analizzarli come JSON, è valido per farlo. Ma non sono dati strutturati. JSON è principalmente inventato come formato di interscambio »che viene utilizzato per dati strutturati» che può essere un oggetto o un array.
Onur Yıldırım,

1
OK, quindi penso che siamo d'accordo. I primitivi sono JSON validi in base alle specifiche, ma non sono "strutture". Va bene. Ma hai detto "Argomento: valori come true, false, null sono validi JSON (?). Fatto: sì e no!" - Il fatto è che JSON è valido secondo le specifiche. Le opinioni sul fatto che siano utili o meno sono irrilevanti per questo fatto.
Relequestual il

20

Se il server sta rispondendo con JSON, avrebbe un application/jsontipo di contenuto, se sta rispondendo con un semplice messaggio di testo, dovrebbe avere un text/plaintipo di contenuto. Assicurarsi che il server stia rispondendo con il tipo di contenuto corretto e verificarlo.


4
Questo è sbagliato, ci sono molti altri mediatype compatibili con json. Inoltre overrideMimeTypepuò sovrascrivere l'intestazione del tipo di contenuto.
Knu,

14

quando si utilizza jQuery $.ajax()la risposta avrà la responseJSONproprietà se la risposta fosse JSON, questo potrebbe essere verificato in questo modo:

if (xhr.hasOwnProperty('responseJSON')) {}

3
Questo è il sospetto che sia davvero la risposta che la maggior parte delle persone sta cercando, probabilmente anche l'OP
Kirby,

1
Questo è molto più elegante dell'uso del blocco try catch
Anurag Sinha,

6

Mi piace la risposta migliore ma se è una stringa vuota restituisce true. Quindi ecco una soluzione:

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;
}

var json non viene utilizzato? o solo per cogliere l'errore?
stackdave,

5
var parsedData;

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

Tuttavia, ti suggerirò che la tua chiamata / servizio http dovrebbe restituire sempre i dati nello stesso formato. Quindi, se hai un errore, allora dovresti avere un oggetto JSON che avvolge questo errore:

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

E magari utilizzare, oltre allo stato HTTP, un codice 5xx.


5

Bene ... dipende dal modo in cui stai ricevendo i tuoi dati. Penso che il server stia rispondendo con una stringa formattata JSON (usando json_encode () in PHP, ad es.). Se stai usando un post JQuery e imposti i dati di risposta in un formato JSON ed è un JSON non valido, questo produrrà un errore:

$.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!"); }
});

Ma, se stai usando il tipo response come testo, devi usare $ .parseJSON. Secondo il sito jquery: "Il passaggio in una stringa JSON non valida può comportare il lancio di un'eccezione". Quindi il tuo codice sarà:

$.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',
});

a meno che, naturalmente, non si stia tentando di analizzare il testo dell'errore nella funzione di errore nell'esempio precedente e non si sia sicuri che si tratti di JSON ...
Kirby,

Ottima risposta, anche se responsevuota, andrà a success: '(
Henrik Petterson,

4

Probabilmente ci sono dei test che puoi fare, per esempio se sai che il JSON restituito sarà sempre circondato da {e} quindi potresti provare per quei caratteri, o qualche altro metodo hacky. Oppure potresti usare la libreria JS di json.org per provare ad analizzarla e verificare se ha esito positivo.

Vorrei tuttavia suggerire un approccio diverso. Lo script PHP attualmente restituisce JSON se la chiamata ha esito positivo, ma qualcos'altro in caso contrario. Perchè no restituire sempre JSON?

Per esempio

Chiamata riuscita:

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

Chiamata errata:

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

Ciò renderebbe molto più semplice la scrittura del lato client JS: tutto ciò che devi fare è controllare il membro "status" e agire di conseguenza.


4

Uso solo 2 righe per eseguire ciò:

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

È tutto!

Ma tieni presente che ci sono 2 trap:
1. JSON.parse(null)restituisce null
2. Qualsiasi numero o stringa può essere analizzato con il JSON.parse()metodo.
   JSON.parse("5")ritorni 5
   JSON.parse(5)ritorni5

Facciamo un po 'di gioco sul codice:

// 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

Ho creato un violino per questa risposta su jsfiddle.net/fatmonk/gpn4eyav che include la possibilità di aggiungere anche i tuoi dati di test utente. Mi sembra la base di una buona funzione di libreria, ma vorrei capire di più sul motivo per cui Test 1 non è un array JSON valido.
Fat Monk,

Perché un array deve essere specificato usando [e ]. Ad esempio, [1, 2, 3]è un array di numeri. ["a", "b", "c"]è un array di stringhe. Ed [{"a":1}, {"b":2}]è un array JSON. Il tuo lavoro su jsfiddle sembra davvero utile!
efkan,

Così semplice?! Quindi Test 1 è un oggetto JSON e Test 2 è un array JSON costituito da un singolo elemento oggetto JSON. L'ho capito bene?
Fat Monk,

La domanda contrassegnata come possibile duplicato di questo ( stackoverflow.com/questions/3710204/… ) mi chiede di raggiungere questo obiettivo senza usare try / catch, quindi ho biforcuto il mio violino per cercare di raggiungere anche quell'obiettivo. Il fork è su jsfiddle.net/fatmonk/827jsuvr e funziona con tutti i test sopra tranne il Test 3 che presenta errori JSON.parse. Qualcuno può consigliare come evitare quell'errore senza usare try?
Fat Monk,

L' jsfiddleapplicazione genera un errore a causa del Test 3 non ha un'espressione JSON valida. Quindi un try-catchdeve essere usato per catturare quell'errore e per valutare qualsiasi errore poiché l'espressione non è JSON quando analizza come il Test 3 sopra:try { JSON.parse(data3) } catch(e) { isValidJSON = false }
efkan

2

Potresti provare a decodificarlo e catturare l' eccezione (nativa o json2.js ):

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

Tuttavia, suggerirei di rendere la risposta sempre valida JSON. Se ricevi un errore dalla tua query MySQL, rispedisci semplicemente JSON con l'errore:

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

E poi:

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

2

Avvertenza: per metodi basati suJSON.parse - Anche le matrici e le virgolette racchiudono le stringhe (es. console.log(JSON.parse('[3]'), JSON.parse('"\uD800"')))

Per evitare tutte le primitive JSON non oggetto (booleano, null, array, numero, stringa), suggerisco di utilizzare quanto segue:

/* 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
    }
}

Spiegazione del codice

  • !! o - Not falsy (esclude null, che si registra come typeof 'oggetto')
  • (typeof o === 'oggetto') - Esclude booleano, numero e stringa
  • ! Array.isArray (o) - Escludi matrici (che si registrano come typeof 'oggetto')
  • prova ... JSON.stringify / JSON.parse - Chiede al motore JavaScript di determinare se JSON valido

Perché non usare la risposta hasJsonStructure ()?

Contare su toString() non è una buona idea. Questo perché motori JavaScript diversi possono restituire una rappresentazione di stringa diversa. In generale, i metodi che si basano su questo possono fallire in ambienti diversi o possono essere soggetti a guasti in seguito qualora il motore dovesse mai cambiare il risultato della stringa

Perché catturare un'eccezione non è un hack?

È stato sollevato il fatto che catturare un'eccezione per determinare la validità di qualcosa non è mai la strada giusta da percorrere. Questo è generalmente un buon consiglio, ma non sempre. In questo caso, la rilevazione delle eccezioni è probabilmente la strada migliore perché si basa sull'implementazione del motore JavaScript di convalida dei dati JSON.

Affidarsi al motore JS offre i seguenti vantaggi:

  1. Più approfondito e continuamente aggiornato con il variare delle specifiche JSON
  2. Probabilmente correre più veloce (dato che è un codice di livello inferiore)

Quando viene data la possibilità di appoggiarsi al motore JavaScript, suggerirei di farlo. Soprattutto in questo caso. Anche se può sentirsi hacky per intercettare un'eccezione, sei davvero solo gestire due possibili stati di ritorno da un metodo esterno.


1

Ecco un codice con qualche piccola modifica nella risposta di Bourne. Come JSON.parse (numero) funziona bene senza alcuna eccezione, quindi è stato aggiunto isNaN.

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

0

Tutte le stringhe json iniziano con '{' o '[' e terminano con il corrispondente '}' o ']', quindi controlla quello.

Ecco come funziona Angular.js:

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


@DukeDougal cura di chiarire? A volte le persone iniziano il loro json con un "[" ma non è terribilmente comune.
carlin.scott,

1
È necessario analizzarlo per capire se è valido JSON. Se non è JSON non valido, non è JSON. La domanda è "come dire se una stringa è JSON o no?". Secondo il tuo approccio, questo sarebbe JSON {fibble - e in realtà non è JSON. Considera anche casi come il numero 1 da solo - che è JSON valido.
Duke Dougal,

1
"Se non è JSON non valido, non è JSON". Il fatto che devi usare la parola "valido" dimostra che stai aggiungendo una qualifica al fatto che è più di un semplice json. La domanda era semplicemente "is json" e il mio esempio di codice risponde perfettamente a quella domanda senza assumere requisiti aggiuntivi.
carlin.scott,

cattiva idea se stai usando alcuni dei sistemi di template e hai qualcosa del genere { someValue }passerà automaticamente la validazione.
ncubica,

@ncubica quindi stai usando un modello per qualcosa di diverso da json, la stringa contiene solo un segnaposto che utilizza parentesi graffe e il motore del modello non riesce a sostituire il segnaposto con il valore reale? Inoltre, tieni presente che, come ho già spiegato a Duke, la domanda originale non menziona la convalida. Volevano solo sapere se sembrava json o no.
carlin.scott,

0

Suggerisco in modalità dattiloscritto:

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

0

Ho usato questo (tipo di mix di risposte diverse, ma comunque):

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

Puoi provare quello seguente perché convalida anche numero, null, stringa ma la risposta sopra contrassegnata non funziona correttamente è solo una correzione della funzione sopra:

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

-1

Oltre alle risposte precedenti, nel caso in cui sia necessario convalidare un formato JSON come "{}", è possibile utilizzare il seguente codice:

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;
}

Esempi di utilizzo:

validateJSON('{}')
true
validateJSON('[]')
false
validateJSON('')
false
validateJSON('2134')
false
validateJSON('{ "Id": 1, "Name": "Coke" }')
true
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.