簡體   English   中英

如何測試字符串是否為 JSON?

[英]How to test if a string is JSON or not?

我有一個簡單的 AJAX 調用,服務器將返回包含有用數據的 JSON 字符串或由 PHP function mysql_error()生成的錯誤消息字符串。 如何測試此數據是 JSON 字符串還是錯誤消息。

使用名為isJSON的 function 會很好,就像您可以使用 function 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;
}

測試結果:

isJson 測試結果

讓我們回顧一下(2019+)。

參數truefalsenull是有效的 JSON (?)

事實:這些原始值是JSON 可解析的,但它們不是格式良好的 JSON 結構 JSON 規范表明 JSON 建立在兩種結構上:名稱/值對(對象)的集合或值的有序列表(數組)。

論點:不應使用異常處理來執行預期的操作。
(這是一條有 25 多個贊成票的評論!)

事實:不! 使用 try/catch 絕對是合法的,尤其是在這種情況下。 否則,你需要做很多字符串分析的工作,比如標記/正則表達式操作; 這將有可怕的表現。

hasJsonStructure()

如果您的目標是檢查某些數據/文本是否具有正確的 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;
    }
}

用法:

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

如果服務器用 JSON 響應,那么它會有一個application/json內容類型,如果它用純文本消息響應,那么它應該有一個text/plain內容類型。 確保服務器以正確的內容類型響應並測試它。

使用jQuery $.ajax() ,如果響應是 JSON,則響應將具有responseJSON屬性,可以這樣測試:

if (xhr.hasOwnProperty('responseJSON')) {}
var parsedData;

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

但是,我會建議您,您的 http 調用/服務應始終以相同格式返回數據。 因此,如果您有錯誤,那么您應該有一個包含此錯誤的 JSON 對象:

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

並且可能使用 5xx 代碼以及 HTTP 狀態。

我喜歡最佳答案,但如果它是空字符串,則返回 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;
}

我只使用 2 行來執行該操作:

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

就這樣!

但請記住,有兩個陷阱:
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 格式的字符串進行響應(例如,在 PHP 中使用 json_encode())。 如果您使用 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 總是會被{}包圍,那么您可以測試這些字符或其他一些hacky 方法。 或者你可以使用json.org JS 庫來嘗試解析它並測試它是否成功。

但是,我建議采用不同的方法。 如果調用成功,您的 PHP 腳本當前返回 JSON,否則返回其他內容。 為什么不總是返回 JSON?

例如

調用成功:

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

錯誤調用:

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

這將使編寫您的客戶端 JS 變得更加容易——您所要做的就是檢查“狀態”成員並相應地采取行動。

這是對 Bourne 的回答進行了一些小的修改的代碼。 由於 JSON.parse(number) 工作正常,沒有任何異常,所以添加了 isNaN。

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

所有 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

我使用了這個(混合了不同的答案,但無論如何):

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

警告:對於依賴JSON.parse方法 - 數組和引號包圍的字符串也將通過(即console.log(JSON.parse('[3]'), JSON.parse('"\?"'))

為了避免所有非對象 JSON 原語(布爾值、空值、數組、數字、字符串),我建議使用以下內容:

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

代碼說明

  • !!o - 不假(不包括 null,它注冊為 typeof 'object')
  • (typeof o === 'object') - 排除布爾值、數字和字符串
  • !Array.isArray(o) - 排除數組(注冊為 typeof 'object')
  • try ... JSON.stringify / JSON.parse - 要求 JavaScript 引擎確定 JSON 是否有效

為什么不使用 hasJsonStructure() 答案?

依賴toString()不是一個好主意。 這是因為不同的 JavaScript 引擎可能返回不同的字符串表示。 通常,依賴於此的方法可能會在不同的環境中失敗,或者如果引擎更改字符串結果,則以后可能會失敗

為什么捕獲異常不是黑客攻擊?

有人提出,捕捉異常來確定某事的有效性從來都不是正確的方法。 這通常是很好的建議,但並非總是如此。 在這種情況下,異常捕獲可能是最佳途徑,因為它依賴於 JavaScript 引擎對 JSON 數據進行驗證的實現。

依靠JS引擎提供以下優勢:

  1. 隨着 JSON 規范的變化,更加全面和持續更新
  2. 可能運行得更快(因為它是較低級別的代碼)

當有機會依靠 JavaScript 引擎時,我建議這樣做。 在這種情況下尤其如此。 盡管捕獲異常可能會讓人感覺很棘手,但您實際上只是在處理來自外部方法的兩種可能的返回狀態。

您可以嘗試對其進行解碼並捕獲異常(本機或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);
}

我建議在打字稿模式下:

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

您可以嘗試以下方法,因為它還可以驗證數字、空值、字符串,但上面標記的答案無法正常工作,它只是對上述功能的修復:

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

我認為類似下面的方法應該可以完成這項工作,它返回解析的 JSON(在有效 JSON 的情況下),因此您不需要再次調用JSON.parse

const tryParseJSON = (s) => {
    if (!s) return false;

    try {
        var o = JSON.parse(s);
        if (o && typeof o === "object") return o;
    }
    catch (e) { }

    return false;
};

如果你不介意lodash

npm i -S lodash

const isPlainObject = require("lodash/isPlainObject"); // cjs
// import {isPlainObject} from "lodash"; // esm
function checkIfJSON(input) {
  const inputStr = typeof input === "string" ? input : JSON.stringify(input);
  try {
    if (isPlainObject(JSON.parse(inputStr))) {
      return true;
    }
  } catch (e) {
    return false;
  }
}

對我來說,我只是通過 2 個正返回條件做到了這一點,

第一個條件- 檢查兩端是否為“{”和“}”

第二個條件- 檢查它是否可以被 JSON 解析

我是怎么做到的

const isJsonStringified = (value) => {
  try {
    const isObject = value.slice(0, 1) === '{' && value.slice(value.length - 1) === '}';
    if (typeof value === 'string' && isObject) {
      JSON.parse(value);
    } else {
      return false;
    }
  } catch (err) {
    return false;
  }
  return true;
};

歡迎 :)

數字和boolean值在JSON.parse()中被接受為有效的json,只需在解析前添加類型驗證

function isJson(str) {

    if(!isNaN(str) || str.toString() == 'true' || str.toString() == 'false'){
        return false;
    }

    try {

        JSON.parse(str);

    } catch (e) {

        return false;

    }

    return true;

}

 export function isJsonString(value) { try { return typeof JSON.parse(value) === 'object'; } catch (e) { return false; } }

這為我處理了大部分必需的案例!

除了之前的答案,如果您需要驗證像“{}”這樣的 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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM