Mam proste wywołanie AJAX, a serwer zwróci ciąg JSON z przydatnymi danymi lub ciąg komunikatu o błędzie utworzony przez funkcję PHP mysql_error()
. Jak mogę sprawdzić, czy te dane są ciągiem JSON lub komunikatem o błędzie.
Byłoby miło użyć funkcji o nazwie isJSON
tak samo, jak można użyć funkcji instanceof
do sprawdzenia, czy coś jest tablicą.
To jest to czego chcę:
if (isJSON(data)){
//do some data stuff
}else{
//report the error
alert(data);
}
javascript
mysql
json
jeffery_the_wind
źródło
źródło
Odpowiedzi:
Użyj JSON.parse
function isJson(str) { try { JSON.parse(str); } catch (e) { return false; } return true; }
źródło
JSON.parse(1234)
LUBJSON.parse(0)
LUBJSON.parse(false)
LUBJSON.parse(null)
wszystko nie zgłosi wyjątku i zwróci wartość true !!. nie używaj tej odpowiedzi1234
,0
,false
, inull
są wszystkie ważne wartości JSON. Jeśli potrzebujesz predykatu, który sprawdza, czy JSON reprezentuje obiekt, musisz zrobić trochę więcej.JSON.parse
wykonuje dużo obliczeń, aby przeanalizować ciąg i przekazuje obiekt json, jeśli się powiedzie, ale odrzucasz wynik, którego niektórzy użytkownicy mogą chcieć użyć. To nie wydaje się być dobre. Zamiast tegoreturn {value: JSON.parse(str), valid: true};
w bloku catchreturn {value: str, valid: false};
.. i zmieniłbym nazwę funkcji natryParse()
.Ten kod to
JSON.parse(1234)
lubJSON.parse(0)
lubJSON.parse(false)
lubJSON.parse(null)
all zwróci wartość true.function isJson(str) { try { JSON.parse(str); } catch (e) { return false; } return true; }
Więc przepisałem kod w ten sposób:
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; }
Wynik testu:
Wynik testu isJson
źródło
return (typeof suspect === "object" && suspect !== null);
Podsumujmy to (dla 2019+).
FAKT : Te prymitywne wartości można analizować w formacie JSON, ale nie są one poprawnie sformułowanymi strukturami JSON . Specyfikacja JSON wskazuje, że JSON jest zbudowany na dwóch strukturach: zbiorze par nazwa / wartość (obiekt) lub uporządkowanej liście wartości (tablica).
FAKT : Nie! Używanie try / catch jest zdecydowanie legalne, szczególnie w takim przypadku. W przeciwnym razie musiałbyś wykonać wiele czynności związanych z analizą ciągów, takich jak operacje tokenizacji / regex; co miałoby straszną wydajność.
hasJsonStructure()
Jest to przydatne, jeśli Twoim celem jest sprawdzenie, czy niektóre dane / tekst mają właściwy format wymiany JSON.
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; } }
Stosowanie:
hasJsonStructure('true') // —» false hasJsonStructure('{"x":true}') // —» true hasJsonStructure('[1, false, null]') // —» true
safeJsonParse()
Jest to przydatne, jeśli chcesz zachować ostrożność podczas analizowania niektórych danych do wartości JavaScript.
function safeJsonParse(str) { try { return [null, JSON.parse(str)]; } catch (err) { return [err]; } }
Stosowanie:
const [err, result] = safeJsonParse('[Invalid JSON}'); if (err) { console.log('Failed to parse JSON: ' + err.message); } else { console.log(result); }
źródło
Jeśli serwer odpowiada za pomocą JSON, to miałby
application/json
typ zawartości, jeśli odpowiada zwykłą wiadomością tekstową, powinien miećtext/plain
typ zawartości. Upewnij się, że serwer odpowiada, podając poprawny typ zawartości i przetestuj to.źródło
overrideMimeType
może zastąpić nagłówek typu zawartości.w przypadku użycia
jQuery $.ajax()
odpowiedzi będzie miećresponseJSON
właściwość, jeśli odpowiedź była w formacie JSON, można to sprawdzić w następujący sposób:if (xhr.hasOwnProperty('responseJSON')) {}
źródło
Podoba mi się najlepsza odpowiedź, ale jeśli jest to pusty ciąg, zwraca prawdę. Oto poprawka:
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; }
źródło
var parsedData; try { parsedData = JSON.parse(data) } catch (e) { // is not a valid JSON string }
Jednak zasugeruję, aby Twoje wywołanie / usługa http zawsze zwracały dane w tym samym formacie. Więc jeśli masz błąd, powinieneś mieć obiekt JSON, który opakowuje ten błąd:
{"error" : { "code" : 123, "message" : "Foo not supported" } }
I może użyć oprócz statusu HTTP kodu 5xx.
źródło
Cóż ... To zależy od sposobu otrzymywania danych. Myślę, że serwer odpowiada ciągiem w formacie JSON (używając np. Json_encode () w PHP). Jeśli używasz postu JQuery i ustawisz dane odpowiedzi na format JSON i jest to nieprawidłowy format JSON, spowoduje to błąd:
$.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!"); } });
Ale jeśli używasz odpowiedzi typu jako tekstu, musisz użyć $ .parseJSON. Według witryny jquery: „Przekazanie nieprawidłowego ciągu JSON może spowodować zgłoszenie wyjątku”. W ten sposób twój kod będzie:
$.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', });
źródło
response
jest pusta, trafi dosuccess
: '(Używam tylko 2 linii, aby to zrobić:
var isValidJSON = true; try { JSON.parse(jsonString) } catch { isValidJSON = false }
To wszystko!
Pamiętaj jednak, że istnieją 2 pułapki:
1.
JSON.parse(null)
zwracanull
2. Dowolną liczbę lub ciąg można przeanalizować
JSON.parse()
metodą.JSON.parse("5")
zwraca5
JSON.parse(5)
zwraca5
Pobawmy się kodem:
// 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
źródło
[
i]
. Na przykład[1, 2, 3]
jest tablicą liczb.["a", "b", "c"]
jest tablicą łańcuchową. I[{"a":1}, {"b":2}]
jest tablicą JSON. Twoja praca jsfiddle wydaje się naprawdę przydatna!JSON.parse
. Czy ktoś może doradzić, jak uniknąć tego błędu bez użycia try?jsfiddle
aplikacja zgłasza błąd, ponieważ Test 3 nie ma prawidłowego wyrażenia JSON. Dlategotry-catch
należy użyć a, aby wychwycić ten błąd i ocenić każdy błąd, ponieważ wyrażenie nie jest JSON podczas analizowania, jak w powyższym teście 3:try { JSON.parse(data3) } catch(e) { isValidJSON = false }
Prawdopodobnie istnieją testy, które możesz wykonać, na przykład, jeśli wiesz, że zwracany JSON zawsze będzie otoczony,
{
a}
następnie możesz przetestować te znaki lub inną hacką metodę. Lub możesz użyć biblioteki JS json.org, aby spróbować ją przeanalizować i sprawdzić, czy się powiedzie.Sugerowałbym jednak inne podejście. Twój skrypt PHP obecnie zwraca kod JSON, jeśli wywołanie się powiedzie, ale coś innego, jeśli nie. Dlaczego nie zawsze zwracać JSON?
Na przykład
Udane połączenie:
{ "status": "success", "data": [ <your data here> ] }
Błędne wezwanie:
{ "status": "error", "error": "Database not found" }
To znacznie ułatwiłoby pisanie kodu JS po stronie klienta - wystarczy tylko sprawdzić status członka i odpowiednio zareagować.
źródło
Możesz spróbować go zdekodować i złapać wyjątek (natywny lub json2.js ):
try { newObj = JSON.parse(myJsonString); } catch (e) { console.log('Not JSON'); }
Jednak sugerowałbym, aby odpowiedź była zawsze poprawna w formacie JSON. Jeśli otrzymasz błąd z zapytania MySQL, po prostu odeślij JSON z błędem:
{"error":"The MySQL error string."}
I wtedy:
if (myParsedJSON.error) { console.log('An error occurred: ' + myParsedJSON.error); }
źródło
Ostrzeżenie: w przypadku metod, na których opierają się
JSON.parse
- tablice i łańcuchy otoczone cudzysłowami również przejdą (tj.console.log(JSON.parse('[3]'), JSON.parse('"\uD800"'))
)Aby uniknąć wszystkich prymitywów JSON niebędących obiektami (boolean, null, array, number, string), sugeruję użycie następującego:
/* 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 } }
Objaśnienie kodu
Dlaczego nie skorzystać z odpowiedzi hasJsonStructure ()?
Poleganie na tym
toString()
nie jest dobrym pomysłem. Dzieje się tak, ponieważ różne silniki JavaScript mogą zwracać inną reprezentację ciągu. Ogólnie rzecz biorąc, metody, które na tym polegają, mogą zawieść w różnych środowiskach lub mogą ulec awarii później, jeśli silnik kiedykolwiek zmieni wynik ciąguDlaczego przechwytywanie wyjątku nie jest hakowaniem?
Wychowywano, że złapanie wyjątku w celu określenia ważności czegoś nigdy nie jest właściwą drogą. To generalnie dobra rada, ale nie zawsze. W tym przypadku wychwytywanie wyjątków jest prawdopodobnie najlepszą drogą, ponieważ opiera się na implementacji walidacji danych JSON przez silnik JavaScript.
Poleganie na silniku JS zapewnia następujące korzyści:
Gdybym miał możliwość oparcia się na silniku JavaScript, radziłbym to zrobić. Szczególnie w tym przypadku. Chociaż wychwycenie wyjątku może wydawać się hackem, tak naprawdę obsługujesz tylko dwa możliwe stany powrotu z metody zewnętrznej.
źródło
Użyłem tego (rodzaj mieszanki różnych odpowiedzi, ale tak czy inaczej):
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('-----------------')
źródło
Oto kod z niewielkimi modyfikacjami w odpowiedzi Bourne'a. Ponieważ JSON.parse (liczba) działa dobrze bez żadnych wyjątków, dodano isNaN.
function isJson(str) { try { JSON.parse(str); } catch (e) { return false; } return isNaN(str); }
źródło
Wszystkie ciągi json zaczynają się od „{” lub „[” i kończą odpowiednim „}” lub „]”, więc po prostu to sprawdź.
Oto, jak robi to 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
źródło
{ someValue }
, jak automatycznie przejdzie walidację.Możesz wypróbować poniższy, ponieważ sprawdza również liczbę, null, ciąg, ale zaznaczona powyżej odpowiedź nie działa poprawnie, to tylko poprawka powyższej funkcji:
function isJson(str) { try { const obj = JSON.parse(str); if (obj && typeof obj === `object`) { return true; } } catch (err) { return false; } return false; }
źródło
Oprócz wcześniejszych odpowiedzi, w przypadku konieczności zweryfikowania formatu JSON, takiego jak „{}”, możesz użyć następującego kodu:
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; }
Przykłady użycia:
validateJSON('{}') true validateJSON('[]') false validateJSON('') false validateJSON('2134') false validateJSON('{ "Id": 1, "Name": "Coke" }') true