简体   繁体   English

NodeJS:TypeError:无法读取未定义的属性“ json”

[英]NodeJS: TypeError: Cannot read property 'json' of undefined

I'm creating a CronJob that calls an API and store its response in the database: 我正在创建一个调用API的CronJob,并将其响应存储在数据库中:

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

It works fine, however I receive a TypeError: Cannot read property 'json' of undefined 它工作正常,但是我收到TypeError: Cannot read property 'json' of undefined

I'm using the same function to update the database I use when updating by my API: 我正在使用相同的功能来更新通过API更新时使用的数据库:

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

The TypeError happens in the return res.json(currency) , and it only happens when it's called by the CronJob. TypeError发生在return res.json(currency) ,并且仅在CronJob调用时发生。 When I put new information by API, it doesn't show any error. 当我通过API放置新信息时,它不会显示任何错误。

I think it happens because when I call the function in CronJob , I just pass the req by parameter, but I don't know how to solve it. 我认为发生这种情况是因为当我在CronJob调用该函数时,我只是通过参数传递了req ,但是我不知道如何解决它。 What am I supposed to do? 我应该做些什么?

Thanks in advance! 提前致谢!

There's a famous saying which says that you can solve almost any problem in CS by adding another layer of indirection. 有句著名的谚语说,您可以通过添加另一层间接来解决CS中的几乎所有问题。 This is one of those cases: 这是其中一种情况:

Instead of of declaring your module as: 而不是将模块声明为:

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

Separate the logic from the route-logic: 将逻辑与路由逻辑分开:

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

Now the route can call update() and the cron-job can call getCurrency() directly. 现在,路由可以调用update() ,而cron-job可以直接调用getCurrency()

It's because both req and res is undefined (or atleast not the proper request and response object) when the route is not requested by client (which is the case here). 这是因为当客户端未请求路由时, reqresundefined (或者至少不是正确的requestresponse对象)(在这种情况下)。

Simplest solution I can think of is mock (or make an actual call) a client call in your cron job by using modules like axios , request , request-promise (with Promise wrapper on top of request) like: 我能想到的最简单的解决方案是通过使用axiosrequestrequest-promise (在Promise包装器位于request之上)之类的模块在cron作业中模拟(或进行实际调用)客户端调用:

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

Since you can execute the db methods, a simpler alternative would be to directly execute Currency.findByIdAndUpdate in your cron job. 由于您可以执行db方法,因此一个更简单的选择是直接在cron作业中执行Currency.findByIdAndUpdate I don't see any reason why you would want to call your route in your code. 我看不出您为什么要在代码中调用route任何原因。

Ok, maybe my approach isn't the best, but since I'm passing an undefined object to update() , and I don't need the response, I edited the update function: 好的,也许我的方法不是最好的,但是由于我向undefined 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);
    }
  }

So, since res is undefined, it doesn't return anything. 因此,由于res未定义,因此不会返回任何内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM