AJAX: ¿Compruebe si una cadena es JSON?

83

Mi JavaScript a veces falla en esta línea:

var json = eval('(' + this.responseText + ')');

Los bloqueos se producen cuando el argumento de eval()no es JSON. ¿Hay alguna forma de verificar si la cadena es JSON antes de realizar esta llamada?

No quiero usar un marco, ¿hay alguna forma de hacer que esto funcione usando solo eval()? (Hay una buena razón, lo prometo).

Nick Heiner
fuente
Puede intentar JSON.parse () en un intento / captura ... si puede detectar, no es un marcado JSON válido. Por supuesto, eso es algo ineficiente, je ... ¿Podría darme un ejemplo del marcado JSON no válido que está obteniendo?
Warty

Respuestas:

157

Si incluye el analizador JSON de json.org, puede usar su función parse () y simplemente envolverlo en un try / catch, así:

try
{
   var json = JSON.parse(this.responseText);
}
catch(e)
{
   alert('invalid json');
}

Algo así probablemente haría lo que quieres.

brettkelly
fuente
9
usando jQuery.parseJSON (..) no necesitaría incluir json.org
RayLoveless
1
@Raymo OP no mencionó el uso de jQuery y json2.js en menos de la mitad del tamaño de jQuery (en términos de tamaño de archivo).
brettkelly
Analizar una cadena completa es una mala práctica, y lanzar una excepción puede causar un retraso
redolent
no lanzará una excepción si envía una cadena de números
Hesham Yassin
21

La suya es la alternativa de jQuery ...

try
{
  var jsonObject = jQuery.parseJSON(yourJsonString);
}
catch(e)
{
  // handle error 
}
Ray sin amor
fuente
15

Le recomiendo que utilice una biblioteca JSON de JavaScript para serializar desde y hacia JSON. eval()es un riesgo de seguridad que nunca debe usarse a menos que esté absolutamente seguro de que su entrada está desinfectada y es segura.

Con una biblioteca JSON en su lugar, simplemente ajuste la llamada a su parse()equivalente en un bloque try / catch para manejar entradas que no sean JSON:

try
{
  var jsonObject = JSON.parse(yourJsonString);
}
catch(e)
{
  // handle error 
}
Håvard S
fuente
2

Quizás esto ayude: con este código, puede obtener directamente sus datos ...

<!DOCTYPE html>
<html>
<body>

<h3>Open console, please, to view result!</h3>
<p id="demo"></p>

<script>
var tryJSON = function (test) {
	try {
	    JSON.parse(test);
	}
	catch(err) {
    	// maybe you need to escape this… (or not)
	    test = '"'+test.replace(/\\?"/g,'\\"')+'"';
	}
	eval('test = '+test);
	console.debug('Try json:', test);
};

// test with string…
var test = 'bonjour "mister"';
tryJSON(test);
// test with JSON…
var test = '{"fr-FR": "<p>Ceci est un texte en français !</p>","en-GB": "<p>And here, a text in english!</p>","nl-NL": "","es-ES": ""}';
tryJSON(test);
</script>

</body>
</html>

Dujardin Emmanuel
fuente
Hay muchas formas alternativas de lograr el mismo resultado, usar eval () probablemente sea la menos apropiada.
David
0

El problema de depender del try-catchenfoque es que JSON.parse('123') = 123no generará una excepción. Por lo tanto, además de try-catch, debemos verificar el tipo de la siguiente manera:

function isJsonStr(str) {
    var parsedStr = str;
    try {
        parsedStr = JSON.parse(str);
    } catch (e) {
        return false;
    }
    return typeof parsedStr == 'object'
}
Hesham Yassin
fuente
0

¿Por qué no puede simplemente comprobar cuál es la respuesta? Es más eficiente.

var result;

if (response.headers['Content-Type'] === 'application/json')
    result = JSON.parse(this.responseText);
else
    result = this.responseText;

screen1

ADMITIR
fuente
-1

Hay una pequeña biblioteca que verifica los tipos de JavaScript: is.js

is.json({foo: 'bar'});
=> true

// functions are returning as false
is.json(toString);
=> false

is.not.json([]);
=> true

is.all.json({}, 1);
=> false

is.any.json({}, 2);
=> true

// 'all' and 'any' interfaces can also take array parameter
is.all.json([{}, {foo: 'bar'}]);
=> true

En realidad is.js es mucho más que esto, algunas menciones honoríficas:

var obj = document.createElement('div');
is.domNode(obj);
=> true

is.error(new Error());
=> true

is.function(toString);
=> true

is.chrome();
=> true if current browser is chrome


Ramazan Polat
fuente