Pesquisa de site

javascript - Como testar se uma string é JSON ou não?


Eu tenho uma chamada AJAX simples, e o servidor retornará ou uma string JSON com dados úteis ou uma string de mensagem de erro produzida pela função PHP mysql_error(). Como posso testar se esses dados são uma string JSON ou a mensagem de erro.

Seria bom usar uma função chamada isJSON, assim como você pode usar a função instanceof para testar se algo é um Array.

Isto é o que eu quero:

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

Resposta #1

Use JSON.parse

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

Resposta #2

Usar JSON.parse() possui algumas desvantagens:

  1. JSON.parse(1234) ou
  2. JSON.parse(0) ou
  3. JSON.parse(false) ou
  4. JSON.parse(null)

todos retornarão verdadeiro.

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

function testIsJson(value, expected) {
  console.log(`Expected: ${expected}, Actual: ${isJson(value)}`); 
}

// All of the following codes are expected to return false.
// But actually returns true.
testIsJson(1234, false);
testIsJson(0, false);
testIsJson(false, false);
testIsJson(null, false);

Código que lida com falsos positivos

Então eu reescrevi o código desta forma:

function isJson(item) {
  let value = typeof item !== "string" ? JSON.stringify(item) : item;    
  try {
    value = JSON.parse(value);
  } catch (e) {
    return false;
  }
    
  return typeof value === "object" && value !== null;
}

Resultado do teste:

function isJson(item) {
  let value = typeof item !== "string" ? JSON.stringify(item) : item;
  try {
    value = JSON.parse(value);
  } catch (e) {
    return false;
  }

  return typeof value === "object" && value !== null;
}

function testIsJson(value, expected) {
  console.log(`Expected: ${expected}, Actual: ${isJson(value)}`);
}

const validJson = { "foo": "bar" };
const notValidJson = '{ "foo": "bar" } invalid';

// expected: true
testIsJson(validJson, true);

// expected: false
testIsJson(1234, false);
testIsJson(0, false);
testIsJson(notValidJson, false);
testIsJson(false, false);
testIsJson(null, false);

Resposta #3

Vamos recapitular isso (para 2019+).

Argumento: Valores como true, false, null são JSON válidos (?)

FATO: Esses valores primitivos são analisáveis por JSON, mas não são estruturas JSON bem formadas. A especificação do JSON indica que o JSON é construído sobre duas estruturas: uma coleção de pares nome/valor (objeto) ou uma lista ordenada de valores (array).

Argumento: O tratamento de exceções não deve ser usado para fazer algo esperado.
(Este é um comentário que tem mais de 25 votos positivos!)

FATO: Não! É definitivamente legal usar try/catch, especialmente em um caso como este. Caso contrário, você precisaria fazer muitas análises de strings, como tokenização/operções com regex; o que teria um desempenho terrível.

hasJsonStructure()

Isso é útil se o seu objetivo é verificar se alguns dados/texto estão no formato de intercâmbio JSON adequado.

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 isso é útil se você quiser ter cuidado ao analisar alguns dados para um valor 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);
}

Resposta #4

Se o servidor estiver respondendo com JSON, então ele terá um application/json como tipo de conteúdo; se estiver respondendo com uma mensagem de texto simples, então deve ter um text/plain como tipo de conteúdo. Certifique-se de que o servidor está respondendo com o tipo de conteúdo correto e teste isso.

Resposta #5

Ao usar jQuery $.ajax(), a resposta terá a propriedade responseJSON se a resposta for JSON, isso pode ser testado assim:

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

Artigos relacionados