Ответ 1
Использовать JSON.parse
function isJson(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
У меня есть простой вызов AJAX, и сервер вернет либо строку JSON с полезными данными, либо строку сообщения об ошибке, создаваемую функцией PHP mysql_error()
. Как проверить, являются ли эти данные строкой JSON или сообщением об ошибке.
Было бы неплохо использовать функцию под названием isJSON
так же, как вы можете использовать функцию instanceof
для проверки того, что-то является массивом.
Это то, что я хочу:
if (isJSON(data)){
//do some data stuff
}else{
//report the error
alert(data);
}
Использовать JSON.parse
function isJson(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
Этот код JSON.parse(1234)
или JSON.parse(0)
или JSON.parse(false)
или JSON.parse(null)
все вернет true.
function isJson(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
Итак, я переписал код таким образом:
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;
}
Результат тестирования:
Если сервер отвечает JSON, тогда он будет иметь тип содержимого application/json
, если он отвечает простым текстовым сообщением, тогда он должен иметь тип содержимого text/plain
. Убедитесь, что сервер отвечает правильным типом контента и проверит его.
при использовании jQuery $.ajax()
ответ будет иметь свойство responseJSON
, если ответ был JSON, это можно проверить следующим образом:
if (xhr.hasOwnProperty('responseJSON')) {}
Напомним это (для 2019+).
Аргумент: допустимы такие значения, как
true
,false
,null
JSON (?)
ФАКТ: да и нет! Эти примитивные значения являются JSON-разборными, но они не являются правильно сформированными структурами JSON. Спецификация JSON указывает, что JSON построен на двух структурах: совокупности пары имя/значение (объект) или упорядоченном списке значений (массив).
Аргумент: обработка исключений не должна использоваться, чтобы сделать что-то ожидаемое.
(Это комментарий, который имеет 25+ upvotes!)
ФАКТ: нет! Определенно законно использовать try/catch, особенно в таком случае. В противном случае вам нужно будет выполнить множество операций анализа строк, таких как операции токенизации/регулярного выражения; который имел бы ужасную производительность.
hasJsonStructure()
Это полезно, если ваша цель состоит в том, чтобы проверить, имеют ли некоторые данные/текст надлежащий формат обмена JSON.
function hasJsonStructure(str) {
if (typeof str !== 'string') return false;
try {
const result = JSON.parse(str);
return Object.prototype.toString.call(result) === '[object Object]'
|| Array.isArray(result);
} catch (err) {
return false;
}
}
Использование:
hasJsonStructure('true') // —» false
hasJsonStructure('{"x":true}') // —» true
hasJsonStructure('[1, false, null]') // —» true
safeJsonParse()
И это полезно, если вы хотите быть осторожным при разборе некоторых данных на значение JavaScript.
function safeJsonParse(str) {
try {
return [null, JSON.parse(str)];
} catch (err) {
return [err];
}
}
Использование:
const [err, result] = safeJsonParse('[Invalid JSON}');
if (err) {
console.log('Failed to parse JSON: ' + err.message);
} else {
console.log(result);
}
Мне нравится лучший ответ, но если это пустая строка, он возвращает true. Итак, здесь исправление:
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;
}
Ну... Это зависит от того, как вы получаете свои данные. Я думаю, что сервер отвечает с помощью JSON string (используя json_encode() в PHP, например.). Если вы используете сообщение JQuery и устанавливаете данные ответа в формате JSON, и это неправильный JSON, это приведет к ошибке:
$.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!"); }
});
Но если вы используете ответ типа в виде текста, вам нужно использовать $.parseJSON. Согласно сайту jquery: "Передача в некорректной строке JSON может привести к исключению исключения". Таким образом, ваш код будет:
$.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',
});
Есть, вероятно, тесты, которые вы можете сделать, например, если вы знаете, что возвращаемый JSON всегда будет окружен {
и }
, тогда вы можете проверить эти символы или какой-нибудь другой хакерский метод. Или вы можете использовать библиотеку JA json.org, чтобы попытаться разобрать ее и проверить, удастся ли она выполнить.
Я бы предложил другой подход. Ваш PHP script в настоящее время возвращает JSON, если вызов успешный, но что-то еще, если это не так. Почему бы не всегда возвращать JSON?
например.
Успешный вызов:
{ "status": "success", "data": [ <your data here> ] }
Ошибочный вызов:
{ "status": "error", "error": "Database not found" }
Это упростит запись вашей клиентской стороны JS - все, что вам нужно сделать, это проверить член "статус" и действовать соответственно.
var parsedData;
try {
parsedData = JSON.parse(data)
} catch (e) {
// is not a valid JSON string
}
Однако я предлагаю вам, чтобы ваш HTTP-вызов/служба всегда возвращал данные в том же формате. Поэтому, если у вас есть ошибка, вы должны иметь объект JSON, который обертывает эту ошибку:
{"error" : { "code" : 123, "message" : "Foo not supported" } }
И, возможно, используйте так же, как и статус HTTP, код 5xx.
Вы можете попробовать его расшифровать и перехватить исключение (native или json2.js):
try {
newObj = JSON.parse(myJsonString);
} catch (e) {
console.log('Not JSON');
}
Однако я бы предложил сделать ответ всегда действительным JSON. Если вы получите сообщение об ошибке из вашего MySQL-запроса, просто отправьте обратно JSON с ошибкой:
{"error":"The MySQL error string."}
И затем:
if (myParsedJSON.error) {
console.log('An error occurred: ' + myParsedJSON.error);
}
Я использую только 2 строки, чтобы выполнить это:
var isValidJSON = true;
try { JSON.parse(jsonString) } catch { isValidJSON = false }
Что все!
Но имейте в виду, что есть 2 ловушки:
1. JSON.parse(null)
возвращает null
2. Любое число или строка может быть проанализирована с помощью метода JSON.parse()
.
JSON.parse("5")
возвращает 5
JSON.parse(5)
возвращает 5
Пусть некоторые играют по коду:
// 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
Все строки json начинаются с '{' или '[' и заканчиваются соответствующими '}' или ']', поэтому просто проверьте это.
Здесь 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
Чтобы создать первый ответ, вместо кода копирования вы можете импортировать этот json-validator с открытым исходным кодом для проверки строки json.
Вот пример использования:
const vaildateJson = require('bit/global/json-validator');
vaildateJson(jsonStr).catch(err => console.log(err))
Я предлагаю в режиме Typescript:
export function stringify(data: any): string {
try {
return JSON.stringify(data)
} catch (e) {
return 'NOT_STRINGIFIABLE!'
}
}
В дополнение к предыдущим ответам, в случае необходимости проверки формата JSON, такого как "{}", вы можете использовать следующий код:
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;
}
Примеры использования:
validateJSON('{}')
true
validateJSON('[]')
false
validateJSON('')
false
validateJSON('2134')
false
validateJSON('{ "Id": 1, "Name": "Coke" }')
true
Приведенные выше ответы вполне приемлемы, но JSON.parse считается дорогим, поэтому вы, скорее всего, захотите сохранить проанализированные данные только в случае их передачи, а не повторного анализа.
function isJson(str) {
if (typeof str !== "string" || '${str}'.length === 0) return [false, str];
let json = "";
let isValid = false;
try {
json = JSON.parse(str);
isValid = true;
} catch (e) {
isValid = false
}
if (!json || typeof json !== "object") isValid = false;
return [isValid, json]
};
//Usage
const [isValid, json] = isJson("[\"abc\", \"123\"]");
if(isValid) console.log(json);