Как разобрать JSON с помощью Node.js?


972

Как мне проанализировать JSON с помощью Node.js? Есть ли какой-нибудь модуль, который будет проверять и анализировать JSON безопасно?

Ответы:


1100

Вы можете просто использовать JSON.parse.

Определение JSONобъекта является частью спецификации ECMAScript 5 . node.js построен на движке Google Chrome V8 , который соответствует стандарту ECMA. Следовательно, node.js также имеет глобальный объект [docs] .JSON

Примечание - JSON.parseможет связать текущий поток, потому что это синхронный метод. Поэтому, если вы планируете анализировать большие объекты JSON, используйте потоковый анализатор JSON.


Кто-нибудь знает, почему этого нет в официальной документации? Или, если он есть, где его найти?
snapfractalpop

34
@snapfractalpop: документация описывает только функции и т. д., которые являются частью node.js. Стандартные функции JavaScript являются частью V8 , на котором построен node.js. Я обновил ответ соответственно.
Феликс Клинг

1
@FelixKling Что бы это ни стоило, здесь есть куча материала на вики-узле github: github.com/joyent/node/wiki/…
damianb

здесь я опубликовал демо-версию, где вы можете посмотреть и поиграть с этим ответом онлайн (пример разбора находится в файле app.js - затем нажмите кнопку запуска и увидите результат в терминале): по ссылке вы можете изменить код и увидеть влияние ...
Натан г

Ваш ответ требует предварительного знания синтаксиса JavaScript. Насколько сложно будет показать пример использования? JSON.parse (ул); // удобен для новичков и, следовательно, лучше ответ
webb

661

Вы можете требовать файлы .json.

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

Например, если у вас есть config.jsonфайл в том же каталоге, что и файл исходного кода, который вы используете:

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

или (расширение файла может быть опущено):

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

обратите внимание , что requireэто синхронное и читает только файл один раз , следующие вызовы возвращают результат из кэша

Также обратите внимание, что вы должны использовать это только для локальных файлов под вашим абсолютным контролем, так как он потенциально выполняет любой код в файле.


4
Если вы используете этот метод для анализа файла, обязательно примите во внимание путь для запроса. Например, вам может потребоваться сделать что-то вроде этого: require './file-name-with-no-extension' (например, если файл находится в текущем каталоге)
SnapShot

94
Обратите внимание, что ответ кэшируется. Например, если вы укажете выше требование функции в функции, вызов функции, изменение файла JSON и повторный вызов функции, вы получите старую версию файла JSON. Поймал меня пару раз!
Бен Клейтон,

15
Обратите внимание, что requireэто синхронно. Если вы хотите использовать дружественное асинхронное использование fs.readFileвместо этогоJSON.parse
Эван Моран

29
Будет ли этот подход обрабатывать файл как JavaScript, таким образом потенциально запуская произвольный код в файле .json?
d11wtq

15
Простое примечание: не забудьте использовать .jsonрасширение! Если ваш файл НЕ имеет .jsonрасширения, require не будет обрабатывать его как файл json.
Джейсон

323

Вы можете использоватьJSON.parse() .

Вы должны иметь возможность использовать JSONобъект в любой реализации JavaScript, совместимой с ECMAScript 5 . И V8 , на котором построен Node.js, является одним из них.

Примечание. Если вы используете файл JSON для хранения конфиденциальной информации (например, паролей), это неправильный способ сделать это. Посмотрите, как Heroku делает это: https://devcenter.heroku.com/articles/config-vars#setting-up-config-vars-for-a-deployed-application . Узнайте, как ваша платформа делает это, и используйте process.envдля получения конфигурационных переменных из кода.


Разбор строки, содержащей данные JSON

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

Разбор файла, содержащего данные JSON

Вам придется выполнить некоторые файловые операции с fsмодулем.

Асинхронная версия

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

Синхронная версия

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

Вы хотите использовать require? Подумай еще раз!

Иногда вы можете использоватьrequire :

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

Но я не рекомендую это по нескольким причинам:

  1. requireсинхронно Если у вас очень большой JSON-файл, он закроет ваш цикл событий. Вам действительно нужно использовать JSON.parseс fs.readFile.
  2. requireбудет читать файл только один раз . Последующие обращения к requireтому же файлу вернут кэшированную копию. Не очень хорошая идея, если вы хотите прочитать .jsonфайл, который постоянно обновляется. Вы могли бы использовать взломать . Но на данный момент проще использовать fs.
  3. Если ваш файл не имеет .jsonрасширения, requireсодержимое файла не будет обрабатываться как JSON.

Шутки в сторону! ИспользованиеJSON.parse .


load-json-file модуль

Если вы читаете большое количество .jsonфайлов (и если вы очень ленивы), каждый раз становится неудобно писать шаблонный код. Вы можете сохранить некоторые символы с помощью load-json-fileмодуля.

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

Асинхронная версия

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

Синхронная версия

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

Разбор JSON из потоков

Если содержимое JSON передается по сети, необходимо использовать потоковый анализатор JSON. В противном случае он свяжет ваш процессор и закроет цикл обработки событий, пока содержимое JSON не будет полностью передано.

Для этого в NPM доступно множество пакетов . Выберите, что лучше для вас.


Обработка ошибок / Безопасность

Если вы не уверены, что все, что передано, JSON.parse()является допустимым JSON , убедитесь, что JSON.parse()заключили вызов внутрь try/catchблока. Предоставленная пользователем строка JSON может привести к сбою приложения и даже к дырам в безопасности. Убедитесь, что обработка ошибок выполнена, если вы анализируете предоставленный извне JSON.


2
and could even lead to security holesиз любопытства, как?
Natario

6
@natario: здесь речь идет о серверной JS. Предположим, кто-то анализирует пользовательский JSON. Если предполагается, что JSON всегда правильно сформирован, злоумышленник может отправить какой-то искаженный JSON, чтобы вызвать ошибку, которая в случае ее распространения на стороне клиента может раскрыть важную информацию о системе. Или, если JSON был неверно сформирован и содержал некоторый текст <script>..., а ошибка была передана на клиентскую сторону, у вас есть ошибка XSS. Поэтому IMO важно обрабатывать ошибки JSON там, где вы их анализируете.
Сампатрисрис

1
@NickSteele: Однако я изменил «это не рекомендуется» на «я не рекомендую». Я надеюсь, что вы счастливы сейчас.
Сампатрисрис

1
@NickSteele: Учитывая недостатки, которые я перечислил, я не думаю, что это хорошо продуманная функция. Похоже, что некоторые люди думают: «Эй, разве не круто использовать requireJSON?» и даже не стал документировать побочные эффекты. Это также означало, что require принимает файлы на двух языках: JavaScript и JSON (нет, они не одинаковы). Так много для SRP.
Сампатсрис

1
@NickSteele: Да, только для конфига он работает нормально. Но JSON не используется только для конфигурации.
Сампатрисрис

85

используйте объект JSON :

JSON.parse(str);

12
Это просто дублирует верхний ответ. Пожалуйста, рассмотрите возможность его удаления; Вы сохраните очки.
Дан Даскалеску

6
Этот ответ имеет 50 голосов. Согласно правилу 1% , вероятно, 5000 пользователей потратили время на чтение этого ответа, что ничего не добавляет к верхнему. Тот факт, что ему 3 года, только усугубляет проблему :)
Дан Даскалеску

16
@DanDascalescu - Если вы заметите, два ответа были опубликованы в одно и то же время 3 года назад. Они оба предоставляют одинаковую информацию. Это касается всего ТАК, я не собираюсь отбирать половину своих ответов только потому, что они не были приняты.
Марк Кан

8
Я, например, нашел эту серию комментариев довольно интересной, но сам ответ был пустой тратой моего времени. ... Я не уверен, подразумевает ли это, что ответ должен быть удален, потому что тогда я бы не увидел ветку комментариев. Но в противном случае я бы сказал, что да.
MalcolmOcean

7
@DanDascalescu, я считаю, что этот ответ яснее и прямо в точку. Принятый не дает пример использования и сбивает с толку из-за множества ссылок и дополнительных вещей.
andresgottlieb

37

Еще один пример JSON.parse:

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

2
Мне нравится, что этот подход не требует, чтобы файл json был локальным для приложения. Спасибо!
Чарльз Брандт

35

Я хотел бы отметить, что есть альтернативы глобальному объекту JSON. JSON.parseи JSON.stringifyоба синхронны, поэтому, если вы хотите работать с большими объектами, вы можете проверить некоторые из асинхронных модулей JSON.

Посмотрите: https://github.com/joyent/node/wiki/Modules#wiki-parsers-json


1
Это особенно верно, если вы ожидаете данные JSON от входящих соединений. Если неправильно сформированный JSON анализируется JSON.parseвсем вашим приложением process.on('uncaughtException', function(err) { ... });, то это может привести к сбою или, используя , в конечном итоге не будет никакой возможности отправить пользователю сообщение «неправильно сформированный JSON».
Пол

3
Какой из них asyncпарсер? Я не нашел это.
bxshi

3
Связанная страница теперь помечена как «УСТАРЕЩАЯ» и описывает себя как «выцветшая реликвия».
никто

30

Включить node-fsбиблиотеку.

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

Для получения дополнительной информации о библиотеке 'fs' см. Документацию по адресу http://nodejs.org/api/fs.html.


2
Возможно, стоит отметить, что вы должны заключить строку var файла в try / catch на тот случай, если ваш JSON не удастся проанализировать или файл не существует.
Фост

3
Или просто воспользуйтесь обратным вызовом!
Lawx

10

Так как вы не знаете, что ваша строка на самом деле действительна, я бы поставил ее сначала в попытку. Кроме того, поскольку блоки try catch не оптимизируются узлом, я бы поместил все это в другую функцию:

function tryParseJson(str) {
    try {
        return JSON.parse(str);
    } catch (ex) {
        return null;
    }
}

ИЛИ в "асинхронном стиле"

function tryParseJson(str, callback) {
    process.nextTick(function () {
      try {
          callback(null, JSON.parse(str));
      } catch (ex) {
          callback(ex)
      }
    })
}

2
Я просто хочу отметить, что process.nextTick не является aysnc. Это просто откладывает чтение файла до следующего вызова функции в цикле событий JS. Для асинхронного запуска JSON.parse вы должны использовать поток, отличный от основного потока Node.js
Александр Миллс


7

Все здесь рассказывали о JSON.parse, поэтому я подумал сказать что-то еще. Есть отличный модуль Connect со многими промежуточными программами, чтобы сделать разработку приложений проще и лучше. Одним из промежуточных программ является bodyParser . Он анализирует JSON, html-формы и т. Д. Существует также специальное промежуточное ПО для анализа только JSON noop .

Посмотрите на ссылки выше, это может быть очень полезно для вас.



6

как уже упоминалось в других ответах, вы, вероятно, захотите либо потребовать локальный файл json, который, как вы знаете, безопасен и присутствует, например, файл конфигурации:

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

или использовать глобальный объект JSON для анализа строкового значения в объекте:

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

обратите внимание, что когда вам требуется файл, его содержимое оценивается, что создает угрозу безопасности в случае, если это не файл json, а файл js.

здесь я опубликовал демо, где вы можете увидеть оба метода и поиграть с ними онлайн (пример разбора находится в файле app.js - затем нажмите на кнопку «Выполнить» и увидите результат в терминале): http: // staging1 .codefresh.io / лаборатория / API / ENV / JSON-синтаксический анализ, например ,

Вы можете изменить код и увидеть влияние ...


5

Используете JSON для своей конфигурации с Node.js? Прочитайте это и получите навыки настройки более 9000 ...

Примечание. Люди, утверждающие, что data = require ('./ data.json'); это угроза безопасности, и люди с ревностным рвением опровергают ответы людей: вы совершенно и совершенно неправы . Попробуйте поместить не-JSON в этот файл ... Node выдаст вам ошибку, точно так же, как если бы вы делали то же самое с гораздо более медленным и трудным кодом для ручного чтения файла, а затем с последующим JSON.parse (). Пожалуйста, прекратите распространять дезинформацию; ты делаешь больно миру, а не помогаешь. Узел был разработан, чтобы позволить это; это не угроза безопасности!

Правильные приложения входят в 3+ уровня конфигурации:

  1. Конфигурация сервера / контейнера
  2. Конфигурация приложения
  3. (необязательно) Конфигурация арендатора / сообщества / организации
  4. Конфигурация пользователя

Большинство разработчиков относятся к конфигурации своего сервера и приложения так, как будто они могут измениться. Не может Вы можете накладывать изменения из более высоких слоев друг на друга, но вы изменяете базовые требования . Некоторые вещи должны существовать! Сделайте так, чтобы ваш конфиг действовал так, как будто он неизменен, потому что некоторые из них, в основном, как ваш исходный код

Если вы не увидите, что многие вещи не изменятся после запуска, это приведет к анти-шаблонам, таким как засорение вашей конфигурации загрузкой блоков try / catch, и притворство, что вы можете продолжить работу без правильно настроенного приложения. Ты не можешь Если вы можете, это относится к уровню конфигурации сообщества / пользователя, а не к уровню конфигурации сервера / приложения. Вы просто делаете это неправильно. Необязательные элементы должны быть расположены сверху, когда приложение завершает загрузку.

Хватит биться головой об стену: ваш конфиг должен быть очень простым .

Посмотрите, как просто настроить такую ​​сложную инфраструктуру, как независимая от протокола и независимой от источника данных служба, с помощью простого файла конфигурации json и простого файла app.js ...

контейнер-config.js ...

{
    "service": {
        "type"  : "http",
        "name"  : "login",
        "port"  : 8085
    },
    "data": {
        "type"  : "mysql",
        "host"  : "localhost",
        "user"  : "notRoot",
        "pass"  : "oober1337",
        "name"  : "connect"
    }
}

index.js ... (двигатель, который питает все)

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

app.js ... (код, обеспечивающий работу службы, не зависящей от протокола и источника данных)

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

Используя этот шаблон, вы теперь можете загружать файлы конфигурации сообщества и пользователей поверх загруженного приложения, dev ops готов поместить вашу работу в контейнер и масштабировать ее. Вы читаете за мультитенант. Userland изолирован. Теперь вы можете разделить вопросы о том, какой протокол службы вы используете, какой тип базы данных вы используете, и просто сосредоточиться на написании хорошего кода.

Поскольку вы используете слои, вы можете полагаться на единый источник правды для всего в любое время (многоуровневый объект конфигурации) и избегать проверок ошибок на каждом этапе, беспокоясь о "о, черт, как я собираюсь сделать это работать без правильной конфигурации?!? ".


4

Мое решение:

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

Спасибо @eloyesp, я пытался использовать этот код, но продолжаю получать TypeError: path must be a string or Bufferошибки - есть идеи, где начать отладку этой проблемы?
GPP

4

Просто хочу завершить ответ (как я некоторое время боролся с ним), хочу показать, как получить доступ к информации json, этот пример показывает доступ к массиву Json:

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


3

Просто, чтобы сделать это как можно более сложным, и принести как можно больше пакетов ...

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

Это позволяет вам делать:

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

Или, если вы используете async / await:

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

Преимущество перед простым использованием readFileSyncзаключается в том, что ваш Node-сервер может обрабатывать другие запросы во время чтения файла с диска.


2

JSON.parse не обеспечит безопасность анализируемой строки json. Вы должны посмотреть на библиотеку, такую ​​как json-safe-parse или похожую библиотеку.

Со страницы json-safe-parse npm:

JSON.parse великолепен, но у него есть один серьезный недостаток в контексте JavaScript: он позволяет переопределять унаследованные свойства. Это может стать проблемой, если вы анализируете JSON из ненадежного источника (например, пользователя) и вызываете функции, которые вы ожидаете существовать.


2

Используйте функцию попытки Lodash для возврата объекта ошибки, который вы можете обработать с помощью функции isError.

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

3
Можете ли вы объяснить, почему вы добавили .bindвместо использования _.attempt (JSON.parse, str)
steviejay

2

Всегда обязательно используйте JSON.parse в блоке try catch, поскольку узел всегда генерирует непредвиденную ошибку, если в вашем json есть поврежденные данные, поэтому используйте этот код вместо простого JSON.Parse

try{
     JSON.parse(data)
}
catch(e){
   throw new Error("data is corrupted")
  }

1

Если вы хотите добавить некоторые комментарии в ваш JSON и разрешить использовать запятые, вы можете использовать следующую реализацию:

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

Обратите внимание, что это может не сработать, если у вас есть что-то вроде "abc": "foo // bar"вашего JSON. Итак, YMMV.


1

Если исходный файл JSON довольно большой, возможно, стоит рассмотреть асинхронный маршрут с помощью нативного подхода async / await с Node.js 8.0 следующим образом

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

1

Я использую FS-Extra . Мне это очень нравится, потому что - хотя он поддерживает обратные вызовы - он также поддерживает обещания . Так что это просто позволяет мне писать свой код гораздо более читабельным способом:

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модуля и обещает их.

ПРИМЕЧАНИЕ. Вы по-прежнему можете использовать собственные методы Node.js. Они обещаны и скопированы в fs-extra. Смотрите заметки на fs.read()&fs.write()

Так что это в основном все преимущества. Я надеюсь, что другие найдут это полезным.


1

Если вам нужно проанализировать JSON с Node.js безопасным способом (иначе: пользователь может вводить данные или через публичный API), я бы предложил использовать secure-json-parse .

Использование по умолчанию, JSON.parseно оно защитит ваш код от:

const badJson = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "constructor": {"prototype": {"bar": "baz"} } }'

const infected = JSON.parse(badJson)
console.log(infected.x) // print undefined

const x = Object.assign({}, infected)
console.log(x.x) // print 7

const sjson = require('secure-json-parse')
console.log(sjson.parse(badJson)) // it will throw by default, you can ignore malicious data also

0

Вы можете использовать JSON.parse () (это встроенная функция, которая, вероятно, заставит вас заключить ее в операторы try-catch).

Или используйте некоторую библиотеку JSON для анализа npm, что-то вроде json-parse-or



0

NodeJs - это сервер на основе JavaScript , так что вы можете делать то же самое, что и в чистом JavaScript ...

Представьте, что у вас есть этот Json в NodeJs ...

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

И вы можете сделать выше, чтобы получить разобранную версию вашего JSON ...


0

Как уже упоминалось в ответах выше, мы можем использовать JSON.parse()синтаксический анализ строк в JSON. Но перед синтаксическим анализом обязательно проанализируйте правильные данные, иначе это может привести к остановке всего приложения.

это безопасно использовать как это

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

0

Использование JSON.parse(str);. Подробнее об этом читайте здесь .

Вот некоторые примеры:

var jsonStr = '{"result":true, "count":42}';

obj = JSON.parse(jsonStr);

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

-1

Никаких дополнительных модулей не требуется.
Просто используйте,
var parsedObj = JSON.parse(yourObj);
я не думаю, что есть какие-либо проблемы безопасности в связи с этим


-2

Это просто, вы можете конвертировать JSON в строку, используя JSON.stringify(json_obj), и конвертировать строку в JSON, используя JSON.parse("your json string").


2
Вы смотрели верхний ответ на этот вопрос? Ей 3 года и она очень полная. Что вы надеялись внести с помощью тривиальной информации, которую вы предлагаете здесь?
Робби Корнелиссен

2
Теперь давайте не будем придерживаться двойных стандартов
danielmhanover
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.