¿Cómo probar si una cadena es JSON o no?

191

Tengo una simple llamada AJAX, y el servidor devolverá una cadena JSON con datos útiles o una cadena de mensaje de error producida por la función PHP mysql_error(). ¿Cómo puedo probar si estos datos son una cadena JSON o el mensaje de error?

Sería bueno usar una función llamada isJSONal igual que puede usar la función instanceofpara probar si algo es una matriz.

Esto es lo que quiero:

if (isJSON(data)){
    //do some data stuff
}else{
    //report the error
    alert(data);
}
jeffery_the_wind
fuente
Tal vez usarlo eval()si vuelve undefined, entonces no es JSON
MatuDuke
44
Esto se ha resuelto aquí: stackoverflow.com/questions/3710204/…
Reinard
2
Gracias a todos, lo siento, no encontré esa otra publicación antes.
jeffery_the_wind
1
Técnicamente, este no es un engaño de 3710204, ya que uno pregunta si es válido json, que es una barra mucho más alta para pasar que json.
carlin.scott
Posible duplicado de AJAX: ¿Verificar si una cadena es JSON?
Mehdi Dehghani

Respuestas:

320

Utilice JSON.parse

function isJson(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
}
Bourne
fuente
53
El manejo de excepciones no debe usarse para hacer algo esperado.
luisZavaleta
44
JSON.parse(1234)O O JSON.parse(0)O JSON.parse(false)O JSON.parse(null)todo no aumentará la Excepción y volverá verdadero !!. no use esta respuesta
Zalaboza
19
@Zalaboza 1234, 0, false, y nullson válidos todos los valores JSON. Si desea un predicado que pruebe si el JSON representa un objeto, deberá hacer un poco más.
Michael Lang
20
JSON.parsehace muchos cálculos para analizar la cadena y le da el objeto json si tiene éxito, sin embargo, está descartando el resultado que algunos usuarios podrían querer usar. Eso no parece ser bueno. En cambio, return {value: JSON.parse(str), valid: true};y en el bloque catch return {value: str, valid: false};... y cambiaría el nombre de la función a tryParse().
Nawaz
77
@luisZavaleta, entonces, ¿qué sugieres como método?
PirateApp
80

Este código es JSON.parse(1234)o JSON.parse(0)o JSON.parse(false)o JSON.parse(null)todo volverá realidad.

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

Entonces reescribí el código de esta manera:

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

Resultado de la prueba:

Resultado de la prueba isJson

kubosho_
fuente
44
¡Buen trabajo! Su última declaración if podría simplificarse a una simple declaración de devolución como:return (typeof suspect === "object" && suspect !== null);
Nebulosar
38

Recapitulemos esto (para 2019+).

Argumento : Los valores tales como true, false, nullson válidas JSON (?)

HECHO : Estos valores primitivos son JSON-parsable pero no son estructuras JSON bien formadas . La especificación JSON indica que JSON se basa en dos estructuras: una colección de pares de nombre / valor (objeto) o una lista ordenada de valores (matriz).

Argumento : el manejo de excepciones no debe usarse para hacer algo esperado.
(¡Este es un comentario que tiene más de 25 votos a favor!)

HECHO : ¡No! Definitivamente es legal usar try / catch, especialmente en un caso como este. De lo contrario, necesitaría hacer muchas cosas de análisis de cadenas como las operaciones de tokenizing / regex; lo que tendría un desempeño terrible.

hasJsonStructure()

Esto es útil si su objetivo es verificar si algunos datos / texto tienen el formato de intercambio JSON adecuado.

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()

Y esto es útil si desea tener cuidado al analizar algunos datos a un valor de 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);
}
Onur Yıldırım
fuente
1
El enlace a la especificación JSON dice lo siguiente: "Un texto JSON es una secuencia de tokens formados a partir de puntos de código Unicode que se ajustan a la gramática del valor JSON". y "Un valor JSON puede ser un objeto, matriz, número, cadena, verdadero, falso o nulo". - ¿Cómo llegaste a la conclusión de que un JSON solo puede ser objeto o matriz a nivel raíz? No puedo ver esto en la especificación, ni nada relacionado con "estructuras JSON bien formadas"
Relequestual
Lea el segundo párrafo que comienza con "JSON se basa en dos estructuras ..." @ json.org o los párrafos cuarto y quinto de ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
Onur Yıldırım
json.org es solo informativo. Leer la especificación a la que se vinculó no respalda su sugerencia. La especificación menciona RFC 8259 como el último RFC. Eche un vistazo a ejemplos de textos JSON válidos que solo contienen valores tools.ietf.org/html/rfc8259#section-13 - RFC 8259 está diseñado para resolver posibles ambigüedades y confusiones, así.
Relequestual
Lee la respuesta nuevamente. Estoy diciendo que valores como primitivas (es decir, valores de texto en los ejemplos de RFC) no son "estructura" de JSON. No hay ambigüedades. PUEDES analizarlos como JSON, es válido hacerlo. Pero no son datos estructurados. JSON se inventa principalmente como un formato de intercambio »que se utiliza para datos estructurados» que puede ser un objeto o una matriz.
Onur Yıldırım
1
Bien, entonces creo que estamos de acuerdo. Las primitivas son JSON válidas según la especificación, pero no son "estructuras". Esta bien. Pero, usted dijo "Argumento: Valores como verdadero, falso, nulo son válidos JSON (?). Hecho: ¡Sí y no!" - El hecho es el ARE JSON válido según la especificación. Las opiniones sobre si son útiles o no son irrelevantes para ese hecho.
Relequestual
20

Si el servidor responde con JSON, entonces tendría un application/jsontipo de contenido; si responde con un mensaje de texto sin formato, debería tener un text/plaintipo de contenido. Asegúrese de que el servidor responde con el tipo de contenido correcto y pruébelo.

Quentin
fuente
44
Esto está mal, hay muchos otros tipos de medios compatibles con json. Además, overrideMimeTypepuede anular el encabezado de tipo de contenido.
Knu
13

cuando se utiliza jQuery $.ajax()la respuesta tendrá la responseJSONpropiedad si la respuesta fue JSON, esto podría verificarse así:

if (xhr.hasOwnProperty('responseJSON')) {}
rémy
fuente
2
Sospecho que esta es realmente la respuesta que la mayoría de la gente está buscando, probablemente incluso el OP
Kirby
Esto es mucho más elegante que usar el bloque try catch
Anurag Sinha
6

Me gusta la mejor respuesta, pero si es una cadena vacía, devuelve verdadero. Así que aquí hay una solución:

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.
fuente
var json no se usa? o simplemente para atrapar el error?
stackdave
5
var parsedData;

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

Sin embargo, le sugeriré que su llamada / servicio http debe devolver siempre datos en el mismo formato. Entonces, si tiene un error, debe tener un objeto JSON que envuelva este error:

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

Y tal vez use, además del estado HTTP, un código 5xx.

ZER0
fuente
5

Bueno ... Depende de la forma en que recibe sus datos. Creo que el servidor está respondiendo con una cadena con formato JSON (usando json_encode () en PHP, por ejemplo). Si está utilizando la publicación JQuery y establece que los datos de respuesta sean un formato JSON y es un JSON con formato incorrecto, esto producirá un error:

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

Pero, si está usando la respuesta de tipo como texto, necesita usar $ .parseJSON. Según el sitio jquery: "Pasar una cadena JSON con formato incorrecto puede generar una excepción". Así su código será:

$.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
fuente
a menos que, por supuesto, esté intentando analizar el texto de error en la función de error en el ejemplo anterior y no esté seguro de si es JSON ...
Kirby
Gran respuesta, aunque si responseestá vacía, irá a success: '(
Henrik Petterson
4

Probablemente hay pruebas que puede hacer, por ejemplo, si sabe que el JSON devuelto siempre estará rodeado {y }luego podría probar esos caracteres o algún otro método hacky. O puede usar la biblioteca json.org JS para intentar analizarla y comprobar si tiene éxito.

Sin embargo, sugeriría un enfoque diferente. Su script PHP actualmente devuelve JSON si la llamada es exitosa, pero algo más si no lo es. ¿Por qué no siempre devolver JSON?

P.ej

Llamada exitosa:

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

Llamada errónea:

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

Esto facilitaría mucho más la escritura de su JS del lado del cliente: todo lo que tiene que hacer es verificar el miembro de "estado" y actuar en consecuencia.

mdm
fuente
4

Solo uso 2 líneas para realizar eso:

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

¡Eso es todo!

Pero tenga en cuenta que hay 2 trampas:
1. JSON.parse(null)devuelve null
2. Cualquier número o cadena se puede analizar con el JSON.parse()método.
   JSON.parse("5")devuelve 5
   JSON.parse(5)devuelve5

Juguemos un poco sobre el código:

// 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
fuente
He creado un violín para esta respuesta en jsfiddle.net/fatmonk/gpn4eyav que incluye la opción de agregar sus propios datos de prueba de usuario también. Esto me parece la base de una buena función de biblioteca, pero me gustaría entender más sobre por qué la Prueba 1 no es una matriz JSON válida.
Fat Monk
Porque una matriz debe especificarse usando [y ]. Por ejemplo, [1, 2, 3]es una matriz de números. ["a", "b", "c"]es una matriz de cadenas. Y [{"a":1}, {"b":2}]es una matriz JSON. ¡Tu trabajo jsfiddle parece realmente útil!
efkan
¡¿Tan sencillo como eso?! Por lo tanto, la Prueba 1 es un objeto JSON y la Prueba 2 es una matriz JSON que consta de un único elemento de objeto JSON. ¿Lo he entendido bien?
Fat Monk
La pregunta marcada como un posible duplicado de esto ( stackoverflow.com/questions/3710204/… ) pregunta acerca de lograr esto sin usar try / catch, así que he bifurcado mi violín para tratar de lograr ese objetivo también. La bifurcación está en jsfiddle.net/fatmonk/827jsuvr y funciona con todas las pruebas anteriores, excepto la Prueba 3, que tiene errores en el JSON.parse. ¿Alguien puede aconsejar cómo evitar ese error sin usar try?
Fat Monk
Su jsfiddleaplicación arroja un error debido a que la Prueba 3 no tiene una expresión JSON válida. Por lo tanto, try-catchdebe usarse para detectar ese error y evaluar cualquier error, ya que la expresión no es JSON cuando se analiza como en la Prueba 3 anterior:try { JSON.parse(data3) } catch(e) { isValidJSON = false }
efkan
2

Puede intentar decodificarlo y detectar la excepción (nativa o json2.js ):

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

Sin embargo, sugeriría que la respuesta siempre sea válida JSON. Si recibe un error de su consulta MySQL, simplemente envíe JSON con el error:

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

Y entonces:

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

Advertencia: para los métodos en los que se confía JSON.parse: las matrices y las cadenas entre comillas también pasarán (es decir console.log(JSON.parse('[3]'), JSON.parse('"\uD800"'))) .

Para evitar todas las primitivas JSON que no sean objetos (booleano, nulo, matriz, número, cadena), sugiero usar lo siguiente:

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

Explicación del código

  • !! o - No es falso (excluye nulo, que se registra como tipo de 'objeto')
  • (typeof o === 'objeto') - Excluye booleano, número y cadena
  • ! Array.isArray (o) - Excluir matrices (que se registran como typeof 'object')
  • intente ... JSON.stringify / JSON.parse - Pregunta al motor de JavaScript para determinar si JSON es válido

¿Por qué no usar la respuesta hasJsonStructure ()?

Confiar en toString()no es una buena idea. Esto se debe a que diferentes motores de JavaScript pueden devolver una representación de cadena diferente. En general, los métodos que dependen de esto pueden fallar en diferentes entornos o pueden estar sujetos a fallar más tarde si el motor cambia el resultado de la cadena

¿Por qué atrapar una excepción no es un truco?

Se mencionó que atrapar una excepción para determinar la validez de algo nunca es el camino correcto. Este es generalmente un buen consejo, pero no siempre. En este caso, es probable que la captura de excepciones sea la mejor ruta porque se basa en la implementación del motor JavaScript para validar los datos JSON.

Confiar en el motor JS ofrece las siguientes ventajas:

  1. Más exhaustivo y continuamente actualizado a medida que cambian las especificaciones JSON
  2. Es probable que corra más rápido (ya que es un código de nivel inferior)

Cuando tenga la oportunidad de apoyarse en el motor de JavaScript, sugeriría hacerlo. Particularmente en este caso. Aunque puede parecer extraño detectar una excepción, en realidad solo está manejando dos posibles estados de retorno de un método externo.

Ron S.
fuente
1

Aquí hay un código con algunas modificaciones menores en la respuesta de Bourne. Como JSON.parse (número) funciona bien sin ninguna excepción, se agrega isNaN.

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

Todas las cadenas json comienzan con '{' o '[' y terminan con el correspondiente '}' o ']', así que verifíquelo.

Así es como lo hace 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

carlin.scott
fuente
@DukeDougal cuidado de aclarar? A veces las personas comienzan su json con un '[' pero eso no es terriblemente común.
carlin.scott
1
Debe analizarlo para que funcione, es JSON válido. Si es JSON no válido, entonces no es JSON. La pregunta es "¿cómo saber si una cadena es JSON o no?". Según su enfoque, esto sería JSON {fibble, y realmente no es JSON. Considere también casos como el número 1 por sí solo, que es JSON válido.
Duque Dougal

1
"Si es JSON no válido, entonces no es JSON". El hecho de que tenga que usar la palabra "válido" muestra que está agregando una calificación al hecho de que es más que solo json. La pregunta era simplemente "¿es json?" Y mi ejemplo de código responde perfectamente a esa pregunta sin asumir requisitos adicionales.
carlin.scott

mala idea si está utilizando algunos de los sistemas de plantillas y tiene algo así como { someValue }pasará automáticamente la validación.
ncubica

@ncubica, ¿está utilizando una plantilla para algo que no sea json, la cadena solo contiene un marcador de posición que utiliza llaves y el motor de plantilla no puede reemplazar el marcador de posición con el valor real? También tenga en cuenta que, como ya le expliqué a Duke, la pregunta original no menciona la validación. Solo querían saber si parecía json o no.
carlin.scott

0

Sugiero en modo mecanografiado:

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

0

Usé esta (una especie de combinación de diferentes respuestas, pero de todos modos):

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

Puede probar el siguiente porque también valida número, nulo, cadena, pero la respuesta marcada anteriormente no funciona correctamente, es solo una solución de la función anterior:

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

-1

Además de las respuestas anteriores, en caso de que necesite validar un formato JSON como "{}", puede usar el siguiente código:

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

Ejemplos de uso:

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