NodeJS: ошибка типа: не удается прочитать свойство ‘json’ неопределенного типа

#javascript #node.js

#javascript #node.js

Вопрос:

Я создаю CronJob, который вызывает API и сохраняет его ответ в базе данных:

 const CronJob = require("cron").CronJob;
const btc_price_ticker = require("../../controllers/BtcExchange/Ticker");
const currency = require("../../controllers/Currencies/CurrenciesController");

module.exports = new CronJob("* * * * * *", async function() {
  const {
    ticker: { sell }
  } = await btc_price_ticker.getBtcPrice();
  currency
    .update({
      params: {
        id: "5cbdf078f5bcec257fcec792"
      },
      body: {
        exchange_rate: sell,
        lastUpdate: Date.now()
      }
    })
    .catch(error => console.log(error));
});
  

Это работает нормально, однако я получаю TypeError: Cannot read property 'json' of undefined

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

 module.exports = {
  async update(req, res) {
    const currency = await Currency.findByIdAndUpdate(req.params.id, req.body, {
      new: true
    });
    return res.json(currency);
  }
};
  

TypeError Происходит в return res.json(currency) , и это происходит только тогда, когда оно вызывается CronJob. Когда я добавляю новую информацию с помощью API, она не показывает никакой ошибки.

Я думаю, это происходит потому, что когда я вызываю функцию в CronJob , я просто передаю req параметр by, но я не знаю, как это решить. Что я должен делать?

Заранее спасибо!

Комментарии:

1. есть ли у вас выражение с использованием bodyparser

2. Вы вызываете update() без передачи объекта ответа в качестве второго аргумента

3. Да, @alfasin, вы правы. Я почти уверен, что это ошибка, но я не знаю, что я должен передать в качестве объекта ответа

4. @OtavioBonder В идеале вы должны просто вызвать Currency.findByIdAndUpdate или любую другую распространенную функцию util в Corn, а не издеваться req и res

5. Если вы используете cron-job, зачем вам запрос / разрешение с самого начала?

Ответ №1:

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

Вместо объявления вашего модуля как:

 module.exports = {
  async update(req, res) {
    const currency = await Currency.findByIdAndUpdate(req.params.id, req.body, {
      new: true
    });
    return res.json(currency);
  }
};
  

Отделите логику от логики маршрута:

 module.exports = {

  async getCurrency(id, params) {
      const currency = await Currency.findByIdAndUpdate(id, params, {
        new: true
      });
      return currency;
  }

  async update(req, res) {
    const currency = await getCurrency(req.params.id, req.body);
    return res.json(currency);
  }
};
  

Теперь маршрут может вызывать update() , а cron-задание может вызывать getCurrency() напрямую.

Ответ №2:

Хорошо, возможно, мой подход не самый лучший, но поскольку я передаю неопределенный объект в update() , и мне не нужен ответ, я отредактировал update функцию:

 async update(req, res) {
    const currency = await Currency.findByIdAndUpdate(req.params.id, req.body, {
      new: true
    });
    if (res !== undefined) {
      return res.json(currency);
    }
  }
  

Итак, поскольку значение res не определено, оно ничего не возвращает.

Ответ №3:

Это потому, что оба req и res являются undefined (или, по крайней мере, не являются надлежащим request объектом response ), когда маршрут не запрашивается клиентом (что имеет место здесь).

Самое простое решение, о котором я могу подумать, — это имитировать (или выполнить фактический вызов) вызов клиента в вашей cron работе, используя такие модули, как axios , request , request-promise Promise оболочкой поверх запроса), например:

 const rp = require('request-promise')

module.exports = new CronJob("* * * * * *", async function() {
  try {
    const {
      ticker: { sell }
    } = await btc_price_ticker.getBtcPrice();
    // assuming your server is running in localhost, port 3000 and route is 'myapi/:id'
    const url = "http://localhost:3000/myapi/5cbdf078f5bcec257fcec792";
    const options = {
      method: 'GET',
      uri : url,
      json: true,
      body: {
        exchange_rate: sell,
        lastUpdate: Date.now()
      }
    }
    const response = await rp(url);
  } catch(error) {
    console.log(error);
  }
});
  

Поскольку вы можете выполнять db методы, более простой альтернативой было бы прямое выполнение Currency.findByIdAndUpdate в вашем cron задании. Я не вижу никаких причин, по которым вы хотели бы вызвать свой route в своем коде.

Комментарии:

1. Это сделает Corn зависимым от сервера, а также приведет к некоторой задержке.

2. Я не знаю варианта использования, но он использует cron против route . Я просто предоставляю решение для OP. Если бы это был я, я бы выполнил напрямую Currency.findByIdAndUpdate Я не вижу никаких причин вызывать маршрут на вашем собственном сервере для cron

3. Точно, это будет оптимальный подход.

4. Да, @naga-elixir-jar, ваш подход к прямому вызову Currency.findByIdAndUpdate намного лучше. Я буду реализовывать этот способ

5. Что ж, тогда позвольте мне добавить это к ответу 🙂