简体   繁体   English

如何在Node.js中基于Promise的业务级功能中处理Error上返回的对象?

[英]How to deal with returned object on Error in a Promise-based business-level function in Node.js?

I need to create a business level function called "getLocationById" which retrieves some data from a remote server via REST API. 我需要创建一个名为“ getLocationById”的业务级别功能,该功能通过REST API从远程服务器中检索一些数据。 This function is then called by a router to display the data on a web page. 然后,路由器会调用此功能以在网页上显示数据。

If the fetch call is successful, the json result is returned as Promise. 如果获取调用成功,则json结果作为Promise返回。 However, what should be returned to the router if fetch caught an error, eg remote server was not responding or responding with a 500 error? 但是,如果抓取出现错误(例如,远程服务器未响应或响应500错误),应返回路由器什么?

Furthermore, how does the route respond to the error? 此外,路由如何响应错误?

const fetch = require('node-fetch');    
const p_conf = require('../parse_config');  // Configuration

const db = {
    getLocationById: function(locId) {
        fetch(`${p_conf.SERVER_URL}/parse` + '/classes/location', { method: 'GET', headers: {
            'X-Parse-Application-Id': p_conf.APP_ID,
            'X-Parse-REST-API-Key': p_conf.REST_API_KEY
        }})
        .then(res1 => return res1.json())  // RETURN A PROMISE ON SUCCESS
        .catch((error) => {
            console.log(error);
            **WHAT TO RETURN TO THE ROUTER ON ERROR HERE?**
        });
    }
};

EDIT: 编辑:

const db_location = {
    getLocations: function() {
        //res.send("respond with 'locations' router.");
        fetch(`${p_conf.SERVER_URL}/parse` + '/classes/GCUR_LOCATION', { method: 'GET', headers: {
            'X-Parse-Application-Id': p_conf.APP_ID,
            'X-Parse-REST-API-Key': p_conf.REST_API_KEY
        }})
        .then(res1 => res1)
        .catch((error) => {
            console.log(error);
            return Promise.reject(new Error(error));
        })
    }
};

In router: 在路由器中:

router.get('/', function(req, res, next) {
  db_location.getLocations()
  .then(r => res.send(r.json()))      // WHERE AN ERROR WAS THROWN
  .catch((err) => {
    console.log(err);
    return next(err);
  })
});

The following error was thrown: 引发以下错误:

TypeError: Cannot read property 'then' of undefined

on .then(r => res.send(r.json())) .then(r => res.send(r.json())).then(r => res.send(r.json()))

FURTHER EDITS: 进一步编辑:

I then made the following changes. 然后,我进行了以下更改。

business layer 业务层

getLocations: function() {
    // According to node-fetch documentation, fetch returns a Promise object.
    return fetch(`${p_conf.SERVER_URL}/parse` + '/classes/GCUR_LOCATION', { method: 'GET', headers: {
        'X-Parse-Application-Id': p_conf.APP_ID,
        'X-Parse-REST-API-Key': p_conf.REST_API_KEY
      } });

}

Router side: 路由器端:

router.get('/', function(req, res, next) {
   db_location.getLocations()
  .then(r => {
    console.log("r.json(): " + r.json());
    res.send(r.json())})
  .catch((err) => {
    console.log(err);
    return next(err);
  })  
});

Then a new error was thrown: 然后引发了一个新的错误:

(node:10184) UnhandledPromiseRejectionWarning: TypeError: body used already for: http://localhost:1337/parse/classes/GCU
R_LOCATION
    at Response.consumeBody (C:\Work\tmp\node_modules\node-fetch\lib\index.js:326:30)
    at Response.json (C:\Work\tmp\node_modules\node-fetch\lib\index.js:250:22)
    at db_location.getLocations.then.r (C:\Work\tmp\ExpressApps\express-parse-server\routes\locations.js:30:13)
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:228:7)
(node:10184) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing ins
ide of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejectio
n id: 5)
(node:10184) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejection
s that are not handled will terminate the Node.js process with a non-zero exit code.

I believed the fetch function returned a Promise object that can be received by the calling function from the route? 我相信fetch函数返回的Promise对象可以由调用函数从路由接收到吗?

On failure or error, the system needs to do the following: 在发生故障或错误时,系统需要执行以下操作:

  1. Register the error 注册错误
  2. Determine the error type 确定错误类型
  3. Operational errors, such as failing to connect to a server 操作错误,例如无法连接到服务器
  4. Programmer error, which are bugs and needs to be fixed by a developer 程序员错误,它是错误,需要由开发人员修复

Operational errors can be ignored by 操作错误可以被忽略

  1. Unit Testing 单元测试
  2. Taking care of asynchronous and synchronous calls 照顾异步和同步调用
  3. Ensuring all arguments are not passed to the function 确保没有将所有参数传递给函数
  4. Checking for empty arguments, if false, show an error asking the user to provide required fields 检查空参数(如果为false)会显示错误,要求用户提供必填字段

In case of server no connecting, the system should retry after an interval of 60 seconds 如果服务器未连接,则系统应在60秒的间隔后重试

Programming errors: 编程错误:

  • Terminate the function with 'throw ' 用“ throw”终止功能
  • Record the error 记录错误
  • Show the user with an appropriate message, without presenting any technical jargony 向用户显示适当的消息,而不会出现任何技术术语

If your error needs to be handled by the router you either need to not catch() in getLocationById or catch() there, process what you need, and then return Promise.reject(error) so the router can still take care of it downstream. 如果需要通过你要么需要不是路由器处理您的错误catch()getLocationByIdcatch()那里,过程你需要什么,然后返回Promise.reject(error)所以路由器仍然可以照顾它下游。

Something like: 就像是:

 function getLocation() { return Promise.reject('some error') // fake fetch error .then(r => r ) .catch(error => { console.log("handling error in getlocation") // maybe logging or other functions return Promise.reject(error) }) } // in routes: getLocation() .then(r => console.log("sending to user")) .catch(error => console.log("sending error to user: ", error)) 

If you don't have process the error in getLocation() just don't catch it and the error will go down the chain: 如果您没有处理getLocation()中的错误,那就不要抓住它,该错误将沿链式进行:

 function getLocation() { return Promise.reject('some error') .then(r => r ) } // in routes: getLocation() .then(r => console.log("sending to user")) .catch(error => console.log("sending error to user: ", error)) 

Your new edits are close! 您的新修改已接近! First let's clear up a misconception you have about fetch . 首先,让我们澄清一下您对fetch的误解。 Non-OK responses do not result in the fetch promise being rejected. 非OK响应不会导致获取承诺被拒绝。 In order to determine if a call has a successful response, check response.ok . 为了确定呼叫是否有成功的响应,请检查response.ok

Next we need to investigate the json method. 接下来,我们需要研究json方法。 Looking at the documentation we see that it also returns a promise and not JSON. 查看文档,我们看到它还返回一个promise而不是JSON。

Here's a version of your router that's a closer to what you're looking for: 这是您的路由器的一个版本,它更接近您要寻找的版本:

router.get('/', function(req, res, next) {
   db_location.getLocations()
   .then(r => {
        if (r.ok) { return r.json(); }
        throw 'Something went wrong!';
    })
   .then(data => res.json(data))
   .catch((err) => {
        console.log(err);
        next(err);
    })  
});

I think it's great that you're learning promises. 我认为您正在学习承诺真是太好了。 Once you feel comfortable with promises check out async/await . 一旦您对诺言感到满意,请退出async / await It'll make your code easier to read but having an understanding of promises is important. 这将使您的代码更易于阅读,但是了解诺言很重要。

Try switching to the following code and let me know if it works: 尝试切换到以下代码,让我知道它是否有效:

router.get('/', function(req, res, next) {
   return db_location.getLocations().then(r => {
       console.log("r.json(): " + r.json());
       return res.json(r);
     })
     .catch(err => {
       console.log(err);
       return next(err);
   })  
});

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

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