【问题标题】:How to test if a string is JSON or not?如何测试字符串是否为 JSON?
【发布时间】:2012-04-05 23:32:51
【问题描述】:

我有一个简单的 AJAX 调用,服务器将返回包含有用数据的 JSON 字符串或由 PHP 函数 mysql_error() 生成的错误消息字符串。如何测试此数据是 JSON 字符串还是错误消息。

最好使用一个名为 isJSON 的函数,就像您可以使用函数 instanceof 来测试某个东西是否是一个数组一样。

这就是我想要的:

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

【问题讨论】:

标签: javascript mysql json


【解决方案1】:

使用 JSON.parse

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

【讨论】:

  • 不应使用异常处理来做预期的事情。
  • JSON.parse(1234) OR JSON.parse(0) OR JSON.parse(false) OR JSON.parse(null) all 不会引发异常并且会返回 true !!。不要使用这个答案
  • @Zalaboza 12340falsenull 都是有效的 JSON 值。如果你想要一个谓词来测试 JSON 是否代表一个对象,你需要做更多的事情。
  • JSON.parse 进行大量计算来解析字符串,如果成功则为您提供 json 对象,但您会丢弃某些用户可能想要使用的结果。这似乎不太好。我会改为 return {value: JSON.parse(str), valid: true}; 并在 catch 块中 return {value: str, valid: false};.. 并将函数名称更改为 tryParse()
  • @luisZavaleta 那么你有什么建议的方法
【解决方案2】:

如果服务器使用 JSON 响应,那么它将具有 application/json 内容类型,如果它使用纯文本消息响应,那么它应该具有 text/plain 内容类型。确保服务器响应正确的内容类型并进行测试。

【讨论】:

  • 这是错误的,还有很多其他 json 兼容的媒体类型。此外overrideMimeType 可以覆盖内容类型标头。
【解决方案3】:

您可能可以进行一些测试,例如,如果您知道返回的 JSON 总是被 {} 包围,那么您可以测试这些字符或其他一些 hacky 方法。或者你可以使用json.org JS库尝试解析它并测试它是否成功。

不过,我建议采用不同的方法。如果调用成功,您的 PHP 脚本当前会返回 JSON,否则会返回其他内容。为什么不总是返回 JSON?

例如

调用成功:

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

错误调用:

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

这将使编写您的客户端 JS 变得更加容易 - 您所要做的就是检查“状态”成员并采取相应的行动。

【讨论】:

    【解决方案4】:
    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 状态。

    【讨论】:

      【解决方案5】:

      您可以尝试对其进行解码并捕获exception(本机或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);
      }
      

      【讨论】:

        【解决方案6】:

        嗯...这取决于您接收数据的方式。我认为服务器以 JSON 格式响应 字符串(例如在 PHP 中使用 json_encode())。如果您使用 JQuery post 并将响应数据设置为 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...
        • 很好的答案,虽然如果response 为空,它将转到success :'(
        【解决方案7】:

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

        【讨论】:

        • var json 没有使用?还是只是为了捕捉错误?
        【解决方案8】:

        使用jQuery $.ajax() 时,如果响应是JSON,则响应将具有responseJSON 属性,可以这样测试:

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

        【讨论】:

        • 我怀疑这确实是大多数人正在寻找的答案,甚至可能是 OP
        • 这比使用 try catch 块要优雅得多
        【解决方案9】:

        此代码为 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 test result

        【讨论】:

        • 干得好!您的最后一个 if 语句可以简化为一个简单的 return 语句,例如:return (typeof suspect === "object" &amp;&amp; suspect !== null);
        • 如果你用这个函数测试一个.srt文件(字幕文件),它会给出true。
        【解决方案10】:

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

        【讨论】:

        • @DukeDougal 想澄清一下?有时人们以 '[' 开始他们的 json,但这并不常见。
        • 您需要对其进行解析才能确定它是有效的 JSON。如果它是无效的 JSON,那么它不是 JSON。问题是“如何判断字符串是否为 JSON?”。通过您的方法,这将是 JSON {fibble - 它实际上不是 JSON。还要考虑像数字 1 这样的情况 - 这是有效的 JSON。
        • "如果 JSON 无效,则不是 JSON"。您必须使用“有效”一词的事实表明您正在为它不仅仅是 json 的事实添加一个限定。问题只是“它是 json”,我的代码示例完美地回答了这个问题,而无需假设额外的要求。
        • 如果您使用一些模板系统并且您有类似{ someValue } 的东西会自动通过验证。
        • @ncubica 所以你使用的模板不是 json,字符串只包含一个使用花括号的占位符,并且模板引擎无法用实际值替换占位符?还要记住,就像我已经向杜克解释过的那样,最初的问题没有提到验证。他们只想知道它是否看起来像 json。
        【解决方案11】:

        我只用了 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
        

        【讨论】:

        • 我在jsfiddle.net/fatmonk/gpn4eyav 为这个答案创建了一个小提琴,其中还包括添加您自己的用户测试数据的选项。对我来说,这看起来像是一个好的库函数的基础,但我想更多地了解为什么 Test 1 不是有效的 JSON 数组。
        • 因为必须使用[] 指定数组。例如,[1, 2, 3] 是一个数字数组。 ["a", "b", "c"] 是一个字符串数组。而[{"a":1}, {"b":2}] 是一个 JSON 数组。你的 jsfiddle 工作看起来真的很有用!
        • 就这么简单?!所以测试 1 是一个 JSON 对象,而测试 2 是一个由单个 JSON 对象元素组成的 JSON 数组。我理解正确吗?
        • 被标记为可能重复的问题 (stackoverflow.com/questions/3710204/…) 询问如何在不使用 try/catch 的情况下实现此目标,因此我也分叉了我的小提琴以尝试实现该目标。分叉位于 jsfiddle.net/fatmonk/827jsuvr 并适用于上述所有测试,除了测试 3 在JSON.parse 处出错。谁能建议如何在不使用 try 的情况下避免该错误?
        • 您的 jsfiddle 应用程序抛出错误,因为测试 3 没有有效的 JSON 表达式。因此,必须使用 try-catch 来捕获该错误并评估任何错误,因为在像上面的测试 3 那样进行解析时,表达式不是 JSON:try { JSON.parse(data3) } catch(e) { isValidJSON = false }
        【解决方案12】:

        除了之前的答案,如果您需要验证像“{}”这样的 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
        

        【讨论】:

          【解决方案13】:

          让我们回顾一下(2019 年以上)。

          参数truefalsenull 等值是有效的 JSON (?)

          事实:这些原始值是 JSON 可解析,但它们不是格式良好的 JSON 结构JSON specification 表示 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 规范的内容如下:“JSON 文本是由符合 JSON 值语法的 Unicode 代码点形成的标记序列。”和“JSON 值可以是对象、数组、数字、字符串、true、false 或 null。” - 您是如何得出 JSON 只能是根级别的对象或数组的结论的?我在规范中看不到这一点,也没有关于“格式良好的 JSON 结构”的任何内容
          • 阅读以“JSON 建立在两个结构上...”开头的第二段 @json.orgecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf 的第 4 和第 5 段
          • json.org 仅供参考。阅读您链接的规范不支持您的建议。该规范提到 RFC 8259 是最新的 RFC。查看仅包含值 tools.ietf.org/html/rfc8259#section-13 的有效 JSON 文本示例 - RFC 8259 旨在解决可能的歧义和混淆,就像这样。
          • 再次阅读答案。我是说诸如原语之类的值(即 RFC 示例中的文本值)不是 JSON“结构”。没有歧义。您可以将它们解析为 JSON,这样做是有效的。但它们不是结构化数据。 JSON 主要是作为一种交换格式而发明的 » 用于结构化数据 » 可以是对象或数组。
          • 好的,我想我们同意。根据规范,基元是有效的 JSON,但不是“结构”。没关系。但是,您说“参数:true、false、null 等值是有效的 JSON(?)。事实:是和否!” - 事实是根据规范是有效的 JSON。关于它们是否有用的意见与该事实无关。
          【解决方案14】:

          我用过这个(混合了不同的答案,但无论如何):

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

          【讨论】:

            【解决方案15】:

            警告:对于依赖 JSON.parse 的方法 - 数组和引号包围的字符串也会通过(即 console.log(JSON.parse('[3]'), JSON.parse('"\uD800"'))

            为了避免所有非对象 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 引擎可能会返回不同的字符串表示形式。一般来说,依赖于此的方法可能会在不同的环境中失败,或者如果引擎更改字符串结果,以后可能会失败

            为什么捕获异常不是 hack?

            有人提出,捕获异常来确定某事的有效性绝不是正确的方法。这通常是个好建议,但并非总是如此。在这种情况下,异常捕获可能是最佳途径,因为它依赖于 JavaScript 引擎验证 JSON 数据的实现。

            依赖JS引擎有以下优势:

            1. 随着 JSON 规范的变化,更加全面和持续更新
            2. 可能运行得更快(因为它是较低级别的代码)

            如果有机会依靠 JavaScript 引擎,我建议这样做。在这种情况下尤其如此。尽管感觉捕捉异常可能很麻烦,但实际上你只是在处理来自外部方法的两种可能的返回状态。

            【讨论】:

              【解决方案16】:

              这是在 Bourne 的回答中进行了一些细微修改的代码。 由于 JSON.parse(number) 工作正常,没有任何异常,因此添加了 isNaN。

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

              【讨论】:

                【解决方案17】:

                您可以尝试以下一个,因为它也验证数字、空值、字符串,但上面标记的答案不能正常工作,它只是上述函数的修复:

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

                【讨论】:

                  【解决方案18】:

                  我认为类似下面的方法应该可以完成这项工作,它返回解析的 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;
                  };
                  

                  【讨论】:

                    【解决方案19】:

                    如果你不介意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;
                      }
                    }
                    

                    【讨论】:

                      【解决方案20】:

                      对我来说,我只是通过 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;
                      };
                      

                      欢迎 :)

                      【讨论】:

                        猜你喜欢
                        • 2013-08-05
                        • 1970-01-01
                        • 2018-08-10
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-10-18
                        • 2010-12-17
                        • 2010-10-28
                        相关资源
                        最近更新 更多