关于javascript:如何使用Node.js解析JSON?

How to parse JSON using Node.js?

我应该如何使用node.js解析JSON?是否有一些模块可以安全地验证和解析JSON?


您只需使用JSON.parse

JSON对象的定义是ECMAScript 5规范的一部分。node.js基于Google Chrome的V8引擎,该引擎符合ECMA标准。因此,node.js还有一个全局对象JSONdocs。

注-JSON.parse可以绑定当前线程,因为它是同步方法。因此,如果您计划解析大型JSON对象,请使用流式JSON解析器。


您可以需要.json文件。

1
var parsedJSON = require('./file-name');

例如,如果您在与源代码文件相同的目录中有一个config.json文件,那么您将使用:

1
var config = require('./config.json');

或(文件扩展名可以省略):

1
var config = require('./config');

注意,require是同步的,只读取文件一次,后续调用从缓存返回结果。

另外请注意,您应该只将其用于受绝对控制的本地文件,因为它可能执行文件中的任何代码。


您可以使用JSON.parse()

您应该能够在任何ECMAScript 5兼容的javascript实现上使用JSON对象。而构建node.js的V8就是其中之一。

Note: If you're using a JSON file to store sensitive information (e.g. passwords), that's the wrong way to do it. See how Heroku does it: https://devcenter.heroku.com/articles/config-vars#setting-up-config-vars-for-a-deployed-application. Find out how your platform does it, and use process.env to retrieve the config vars from within the code.

分析包含JSON数据的字符串

1
2
var str = '{"name":"John Doe","age": 42 }';
var obj = JSON.parse(str);

分析包含JSON数据的文件

您必须使用fs模块执行一些文件操作。

异步版本

1
2
3
4
5
6
var fs = require('fs');

fs.readFile('/path/to/file.json', 'utf8', function (err, data) {
    if (err) throw err; // we'll not consider error handling for now
    var obj = JSON.parse(data);
});

同步版本

1
2
var fs = require('fs');
var json = JSON.parse(fs.readFileSync('/path/to/file.json', 'utf8'));

你想用require吗?再想一想!

有时可以使用require

1
var obj = require('path/to/file.json');

但是,我不建议这样做的原因有几个:

  • require是同步的。如果您有一个非常大的JSON文件,它将阻塞您的事件循环。你真的需要使用JSON.parsefs.readFile
  • require只读取一次文件。随后对同一文件调用require将返回一个缓存副本。如果您想读取一个持续更新的.json文件,这不是一个好主意。你可以用黑客。但在这一点上,简单地使用fs更容易。
  • 如果您的文件没有.json扩展名,require将不会将文件内容视为json。
  • 说真的!使用JSON.parse

    load-json-file模块

    如果您正在读取大量的.json文件(如果您非常懒惰),那么每次编写样板代码都会变得很烦人。您可以使用load-json-file模块保存一些字符。

    1
    const loadJsonFile = require('load-json-file');

    异步版本

    1
    2
    3
    loadJsonFile('/path/to/file.json').then(json => {
        // `json` contains the parsed object
    });

    同步版本

    1
    let obj = loadJsonFile.sync('/path/to/file.json');

    从流分析JSON

    如果JSON内容通过网络传输,则需要使用流式JSON解析器。否则,它将捆绑处理器并阻塞事件循环,直到JSON内容完全流化。

    在NPM中有很多包可用于此目的。选择最适合你的。

    错误处理/安全

    如果您不确定传递给JSON.parse()的内容是否是有效的json,请确保将对JSON.parse()的调用包含在try/catch块中。用户提供的JSON字符串可能会使应用程序崩溃,甚至可能导致安全漏洞。如果解析外部提供的JSON,请确保已完成错误处理。


    使用json对象:

    1
    JSON.parse(str);


    json.parse的另一个示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var fs = require('fs');
    var file = __dirname + '/config.json';

    fs.readFile(file, 'utf8', function (err, data) {
      if (err) {
        console.log('Error: ' + err);
        return;
      }

      data = JSON.parse(data);

      console.dir(data);
    });


    我想提一下,对于全局JSON对象,还有其他的选择。JSON.parseJSON.stringify都是同步的,因此如果您想处理大对象,可能需要检查一些异步JSON模块。

    看看:https://github.com/joyent/node/wiki/modules wiki解析器json


    包括node-fs库。

    1
    2
    var fs = require("fs");
    var file = JSON.parse(fs.readFileSync("./PATH/data.json","utf8"));

    有关"fs"库的详细信息,请参阅http://nodejs.org/api/fs.html上的文档。


    因为您不知道您的字符串实际上是有效的,所以我首先将它放入一个try catch。另外,由于try catch块没有按节点优化,所以我将把整个功能放到另一个函数中:

    1
    2
    3
    4
    5
    6
    7
    function tryParseJson(str) {
        try {
            return JSON.parse(str);
        } catch (ex) {
            return null;
        }
    }

    或"异步样式"

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function tryParseJson(str, callback) {
        process.nextTick(function () {
          try {
              callback(null, JSON.parse(str));
          } catch (ex) {
              callback(ex)
          }
        })
    }


    分析JSON流?使用JSONStream

    1
    2
    3
    4
    5
    6
    7
    8
    var request = require('request')
      , JSONStream = require('JSONStream')

    request({url: 'http://isaacs.couchone.com/registry/_all_docs'})
        .pipe(JSONStream.parse('rows.*'))
        .pipe(es.mapSync(function (data) {
          return data
        }))

    https://github.com/dominictarr/jsonstream


    这里的每个人都告诉过json.parse,所以我想说点别的。有一个伟大的模块连接许多中间件,使应用程序的开发更容易和更好。其中一个中间件是BodyParser。它解析JSON、HTML表单等,还有一个专门用于JSON解析的中间件noop。

    看看上面的链接,它可能对你很有帮助。


    1
    JSON.parse("your string");

    这就是全部。


    正如这里提到的其他答案,您可能希望要么需要一个本地JSON文件,您知道它是安全的,并且是存在的,比如配置文件:

    1
    var objectFromRequire = require('path/to/my/config.json');

    或者使用全局JSON对象将字符串值解析为对象:

    1
    2
    var stringContainingJson = '"json that is obtained from somewhere"';
    var objectFromParse = JSON.parse(stringContainingJson);

    注意,当您需要一个文件时,会对该文件的内容进行评估,这会带来安全风险,以防它不是JSON文件而是JS文件。

    在这里,我发布了一个演示,您可以在其中看到这两种方法,并在线使用它们(解析示例在app.js文件中-然后单击运行按钮并在终端中看到结果):http://staging1.codefresh.io/labs/api/env/json-parse-example

    您可以修改代码并查看其影响…


    使用json配置node.js?读这个,你的配置技能超过9000…

    Note: People claiming that data = require('./data.json'); is a
    security risk and downvoting people's answers with zealous zeal: You're exactly and completely wrong.
    Try placing non-JSON in that file... Node will give you an error, exactly like it would if you did the same thing with the much slower and harder to code manual file read and then subsequent JSON.parse(). Please stop spreading misinformation; you're hurting the world, not helping. Node was designed to allow this; it is not a security risk!

    正确的应用程序有三层以上的配置:

  • 服务器/容器配置
  • 应用程序配置
  • (可选)租户/社区/组织配置
  • 用户配置
  • 大多数开发人员将他们的服务器和应用程序配置视为可以更改。它不能。你可以从更高的层上相互层叠变化,但是你正在修改基本需求。有些东西需要存在!使您的配置看起来是不可变的,因为其中一些基本上是,就像您的源代码一样。

    如果你看不到很多东西在启动后都不会改变,就会产生反模式,比如在配置加载中乱扔try/catch块,假装你没有正确的设置应用程序就可以继续。不能。如果可以,它属于社区/用户配置层,而不是服务器/应用程序配置层。你只是做错了。当应用程序完成它的引导时,可选的东西应该放在上面。

    别把头撞在墙上了:你的配置应该非常简单。

    看看使用一个简单的json配置文件和简单的app.js文件来设置像协议不可知和数据源不可知的服务框架这样复杂的东西有多简单…

    容器配置JS…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    {
       "service": {
           "type"  :"http",
           "name"  :"login",
           "port"  : 8085
        },
       "data": {
           "type"  :"mysql",
           "host"  :"localhost",
           "user"  :"notRoot",
           "pass"  :"oober1337",
           "name"  :"connect"
        }
    }

    索引…(驱动一切的发动机)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var config      = require('./container-config.json');       // Get our service configuration.
    var data        = require(config.data.type);            // Load our data source plugin ('npm install mysql' for mysql).
    var service     = require(config.service.type);         // Load our service plugin ('http' is built-in to node).
    var processor   = require('./app.js');                  // Load our processor (the code you write).

    var connection  = data.createConnection({ host: config.data.host, user: config.data.user, password: config.data.pass, database: config.data.name });
    var server      = service.createServer(processor);
    connection.connect();
    server.listen(config.service.port, function() { console.log("%s service listening on port %s", config.service.type, config.service.port); });

    应用程序…(支持协议不可知和数据源不可知服务的代码)

    1
    2
    3
    module.exports = function(request, response){
        response.end('Responding to: ' + request.url);
    }

    使用这种模式,您现在可以在启动的应用程序上加载社区和用户配置的内容,dev ops准备将您的工作推送到容器中并对其进行缩放。你读的是多手语。userland是孤立的。现在,您可以将所使用的服务协议、所使用的数据库类型分离开来,只需专注于编写好的代码。

    因为您使用的是层,所以您可以在任何时候(分层配置对象)都依赖于单一的事实源,并避免在每一步都进行错误检查,担心"噢,废话,如果没有正确的配置,我该如何使此工作?""?".


    我的解决方案:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var fs = require('fs');
    var file = __dirname + '/config.json';

    fs.readFile(file, 'utf8', function (err, data) {
        if (err) {
            console.log('Error: ' + err);
            return;
        }

        data = JSON.parse(data);

        console.dir(data);
    });


    只想完成答案(我挣扎了一会儿),想展示如何访问JSON信息,这个例子展示了如何访问JSON数组:

    1
    2
    3
    4
    5
    6
    7
    8
    var request = require('request');
    request('https://server/run?oper=get_groups_joined_by_user_id&user_id=5111298845048832', function (error, response, body) {
      if (!error && response.statusCode == 200) {
        var jsonArr = JSON.parse(body);
        console.log(jsonArr);
        console.log("group id:" + jsonArr[0].id);
      }
    })


    只是为了让事情尽可能复杂,尽可能多的带进包裹…

    1
    2
    3
    4
    5
    const fs = require('fs');
    const bluebird = require('bluebird');
    const _ = require('lodash');
    const readTextFile = _.partial(bluebird.promisify(fs.readFile), _, {encoding:'utf8',flag:'r'});
    const readJsonFile = filename => readTextFile(filename).then(JSON.parse);

    这样可以做到:

    1
    2
    var dataPromise = readJsonFile("foo.json");
    dataPromise.then(console.log);

    或者如果您正在使用异步/等待:

    1
    let data = await readJsonFile("foo.json");

    与仅使用readFileSync相比,优势在于节点服务器可以在文件从磁盘读取时处理其他请求。


    parse不能确保所分析的JSON字符串的安全性。您应该查看类似于JSON安全解析的库或类似的库。

    从json safe parse npm页面:

    JSON.parse is great, but it has one serious flaw in the context of JavaScript: it allows you to override inherited properties. This can become an issue if you are parsing JSON from an untrusted source (eg: a user), and calling functions on it you would expect to exist.


    利用Lodash的尝试函数返回一个错误对象,您可以使用ISerRor函数处理该对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // Returns an error object on failure
    function parseJSON(jsonString) {
       return _.attempt(JSON.parse.bind(null, jsonString));
    }


    // Example Usage
    var goodJson = '{"id":123}';
    var badJson = '{id:123}';
    var goodResult = parseJSON(goodJson);
    var badResult = parseJSON(badJson);

    if (_.isError(goodResult)) {
       console.log('goodResult: handle error');
    } else {
       console.log('goodResult: continue processing');
    }
    // > goodResult: continue processing

    if (_.isError(badResult)) {
       console.log('badResult: handle error');
    } else {
       console.log('badResult: continue processing');
    }
    // > badResult: handle error


    始终确保在try catch块中使用json.parse作为节点。如果JSON中有一些损坏的数据,则始终会引发意外错误,因此请使用此代码而不是简单的json.parse。

    1
    2
    3
    4
    5
    6
    try{
         JSON.parse(data)
    }
    catch(e){
       throw new Error("data is corrupted")
      }


    如果要在JSON中添加一些注释并允许使用后面的逗号,可以使用以下实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var fs = require('fs');

    var data = parseJsData('./message.json');

    console.log('[INFO] data:', data);

    function parseJsData(filename) {
        var json = fs.readFileSync(filename, 'utf8')
            .replace(/\s*\/\/.+/g, '')
            .replace(/,(\s*\})/g, '}')
        ;
        return JSON.parse(json);
    }

    注意,如果您的JSON中有类似于"abc":"foo // bar"的东西,它可能不会很好地工作。所以YMMV。


    如果JSON源文件非常大,那么可能需要考虑使用node.js 8.0通过本机异步/等待方法进行异步路由,如下所示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    const fs = require('fs')

    const fsReadFile = (fileName) => {
        fileName = `${__dirname}/${fileName}`
        return new Promise((resolve, reject) => {
            fs.readFile(fileName, 'utf8', (error, data) => {
                if (!error && data) {
                    resolve(data)
                } else {
                    reject(error);
                }
            });
        })
    }

    async function parseJSON(fileName) {
        try {
            return JSON.parse(await fsReadFile(fileName));
        } catch (err) {
            return { Error: `Something has gone wrong: ${err}` };
        }
    }

    parseJSON('veryBigFile.json')
        .then(res => console.log(res))
        .catch(err => console.log(err))

    我额外使用fs。我很喜欢它,因为-虽然它支持回调-它也支持承诺。所以它只让我以一种更易读的方式编写代码:

    1
    2
    3
    4
    5
    6
    7
    const fs = require('fs-extra');
    fs.readJson("path/to/foo.json").then(obj => {
        //Do dome stuff with obj
    })
    .catch(err => {
        console.error(err);
    });

    它也有许多有用的方法,这些方法与标准的fs模块不配套,除此之外,它还将本地fs模块中的方法连接起来并加以验证。

    NOTE: You can still use the native Node.js methods. They are promisified and copied over to fs-extra. See notes on fs.read() & fs.write()

    所以基本上都是优点。我希望其他人能发现这一点。


    如上所述,我们可以使用JSON.parse()将字符串解析为json。但在分析之前,请确保分析正确的数据,否则可能会导致整个应用程序停机。

    这样使用是安全的

    1
    2
    3
    4
    5
    6
    let parsedObj = {}
    try {
        parsedObj = JSON.parse(data);
    } catch(e) {
        console.log("Cannot parse because data is not is proper json format")
    }

    您可以使用json.parse()(这是一个内置函数,可能会迫使您用try catch语句包装它)。

    或者使用一些JSON解析NPM库,比如JSON解析或


    用这个来保证安全

    1
    var data = JSON.parse(Buffer.concat(arr).toString());

    nodejs是一个基于javascript的服务器,所以您可以用纯javascript来实现这一点…

    假设你在nodejs中有这个json…

    1
    2
    var details = '{"name":"Alireza Dezfoolian","netWorth":"$0" }';
    var obj = JSON.parse(details);

    您可以通过上面的操作获得JSON的解析版本…


    使用JSON.parse(str);。在这里阅读更多。

    以下是一些例子:

    1
    2
    3
    4
    5
    6
    var jsonStr = '{"result":true,"count":42}';

    obj = JSON.parse(jsonStr);

    console.log(obj.count);    //expected output: 42
    console.log(obj.result);   // expected output: true

    不需要进一步的模块。只使用var parsedObj = JSON.parse(yourObj);我认为这方面没有任何安全问题


    很简单,您可以使用JSON.stringify(json_obj)将json转换为字符串,使用JSON.parse("your json string")将字符串转换为json。


    这必须对我大喊大叫:它只对.json文件有效。

    如果文件结尾不同,则不起作用!


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var fs = require('fs');

    fs.readFile('ashish.json',{encoding:'utf8'},function(data,err) {

       if(err)
          throw err;

       else {

       console.log(data.toString());

     }
    })