Как разобрать 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.