UnhandledPromiseRejectionWarning、Express.js 和 Node.js

Posted

技术标签:

【中文标题】UnhandledPromiseRejectionWarning、Express.js 和 Node.js【英文标题】:UnhandledPromiseRejectionWarning, Express.js and Node.js 【发布时间】:2018-12-31 06:27:18 【问题描述】:

我对 Node.jsExpress.js 完全陌生,并且一直在尝试通过一些示例将 Shippo API 集成到我的电子商务网络应用程序中但是我遇到了一些错误,尽管我多次检查了我的代码,但还是无法解决。

我收到 UnhandledPromiseRejectionWarning 错误,根据我在网上阅读的内容,这意味着在我的代码中某处有一个 .then() 部分没有包含“catch”或“what to-do”是请求返回错误。任何帮助将不胜感激。

这是我的代码:

var express = require('express')
var app = express()
var http = require('http');
var Raven = require('raven');
var shippo = require('shippo')('ACCESS_TOKEN');
var engines = require('consolidate');
const bodyParser = require('body-parser');
const path = require('path');
app.use(bodyParser.urlencoded(extended: true));
app.use(bodyParser.json());
app.engine('html', engines.mustache);
app.set('view engine', 'html');
//app.use(express.static(path.join(_dirname,'/')));


app.get('/', function (req, res) 
  res.render('Index.html');
)
app.post('/', function (req, res) 

  var addressFrom  = 
      "object_purpose":"PURCHASE",
      "name": "SENDER_NAME",
      "company":"Shippo",
      "street1":"215 Clayton St.",
      "city":"San Francisco",
      "state":"CA",
      "zip":"94117",
      "country":"US", //iso2 country code
      "phone":"+1 555 341 9393",
      "email":"SENDER_EMAIL",
  ;

  // example address_to object dict
  var addressTo = 
      "object_purpose":"PURCHASE",
      "name": req.body.fnames + ' ' + req.body.lnames,
      "company": req.body.company,
      "street1":req.body.street,
      "city":req.body.city,
      "state":req.body.state,
      "zip":req.body.zipcode,
      "country": req.body.country, //iso2 country code
      "phone":"+1 555 341 9393",
      "email":"support@goshippo.com",
  ;

  // parcel object dict
  var parcelOne = 
      "length":"5",
      "width":"5",
      "height":"5",
      "distance_unit":"in",
      "weight":"2",
      "mass_unit":"lb"
  ;


  var shipment = 
      "object_purpose": "PURCHASE",
      "address_from": addressFrom,
      "address_to": addressTo,
      "parcels": [parcelOne],
      "submission_type": "DROPOFF"
  ;

  shippo.transaction.create(
      "shipment": shipment,
      "servicelevel_token": "ups_standard",
      "carrier_account": 'CARRIER_TOKEN',
      "label_file_type": "PDF"
  )
  .then(function(transaction) 
      shippo.transaction.list(
        "rate": transaction.rate
      )
      .then(function(mpsTransactions) 
          mpsTransactions.results.forEach(function(mpsTransaction)
              if(mpsTransaction.object_status == "SUCCESS") 
                  console.log("Label URL: %s", mpsTransaction.label_url);
                  console.log("Tracking Number: %s", mpsTransaction.tracking_number);
                  console.log("E-Mail: %s", mpsTransaction.object_owner);
                  console.log(mpsTransaction.object_status);
                  res.status(200).send("Label can be found under: " + mpsTransaction.label_url);
               else 
                  // hanlde error transactions
                  console.log("Message: %s", mpsTransactions.messages);
              
          );
      )
  , function(err) 
      // Deal with an error
      console.log("There was an error creating transaction : %s", err.detail);
      res.send("something happened :O")
  );
)
app.post('/successp', function (req, res) 

  var token = req.body.stripeToken; // Using Express
  // Charge the user's card:
var charge = stripe.charges.create(
  amount: 1000,
  currency: "eur",
  description: "Example charge",
  source: token,
, function(err, charge) 
  // asynchronously called
);
 res.send('Thanks!')
)
app.post('/successp', function (req, res) 

  var token = req.body.stripeToken; // Using Express
  // Charge the user's card:
var charge = stripe.charges.create(
  amount: 1000,
  currency: "eur",
  description: "Example charge",
  source: token,
, function(err, charge) 
  // asynchronously called
);
 res.send('Thanks!')
)

app.listen(3000, function () 
  console.log('Example app listening on port 3000!')
)

这是我得到的错误:

侦听端口 3000 的示例应用程序! (节点:2378)UnhandledPromiseRejectionWarning (节点:2378) UnhandledPromiseRejectionWarning:未处理的承诺拒绝。此错误源于在没有 catch 块的情况下抛出异步函数内部,或拒绝未使用 .catch() 处理的承诺。 (拒绝编号:1) (节点:2378)[DEP0018] DeprecationWarning:不推荐使用未处理的承诺拒绝。将来,未处理的 Promise 拒绝将使用非零退出代码终止 Node.js 进程。

我也不完全确定某些行的目的(同样,我对 express 和 node.js 非常陌生)。什么是引擎和胡子?另外,我看到这个示例代码使用了 APP.POST('/succesp', function(req, res)...),那 '/succesp' 到底是什么>?我需要创建另一个 html 文件?还有,开头的“app.use(express.statc([ath.join(_dirnam,'/')));”是什么?

【问题讨论】:

【参考方案1】:

使用then(FN, errorFn) 格式时需要小心一点,因为如果then 中有错误,errorFn 不会捕获它。最好使用then(fn).catch(errorFn)。这将允许上述任何then 中的所有错误过滤到最后一个catch 进行处理。

例如,第一次调用正确捕获错误,第二次没有:

function fn() 
  return Promise.resolve("good")


fn()
  .then(r => 
    throw ("whoops")
  )
  .catch(err => console.log(err)) //<-- catch works here

fn()
  .then(r => 
      throw ("whoops")
    ,
    err => console.log(err) // this can't catch the error above; it will only catch rejections on fn()
  )

它不会显示在 sn-p 中,但如果您查看控制台,您会看到未处理的拒绝错误。

在您的代码中,您可以通过从 shippo.transaction.list 返回承诺来展平承诺链。然后你可以在最后添加一个 catch 来处理错误。

shippo.transaction.create(
    "shipment": shipment,
    "servicelevel_token": "ups_standard",
    "carrier_account": 'CARRIER_TOKEN',
    "label_file_type": "PDF"
)
.then(function(transaction) 
    return shippo.transaction.list(  // return this promise
    "rate": transaction.rate
)
.then(function(mpsTransactions)      // so this can flatten out
    mpsTransactions.results.forEach(function(mpsTransaction)
        if(mpsTransaction.object_status == "SUCCESS") 
            console.log("Label URL: %s", mpsTransaction.label_url);
            console.log("Tracking Number: %s", mpsTransaction.tracking_number);
            console.log("E-Mail: %s", mpsTransaction.object_owner);
            console.log(mpsTransaction.object_status);
            res.status(200).send("Label can be found under: " + mpsTransaction.label_url);
         else 
            // hanlde error transactions
            console.log("Message: %s", mpsTransactions.messages);
        
    );
)
.catch(function(err)    // catch errors
    // Deal with an error
    console.log("There was an error creating transaction : %s", err.detail);
    res.send("something happened :O")
);
)

由于这很难在没有所有部分的情况下在本地运行,我对错误的来源并不肯定,但看起来您正在循环中发送res.status(200).send(),如果它得到可能会导致错误调用了两次。

【讨论】:

【参考方案2】:

如果不阅读完整代码,则在使用 Promises 时不应尝试使用回调函数捕获错误。使用 .catch

在 Promise 中捕获错误

您还应该返回第一个承诺,以便它传递给下一个 .then 函数(如果您打算将 shippo.transaction.list 作为 mpsTransactions 返回)

类似这样的:

 shippo.transaction.create(
 "shipment": shipment,
 "servicelevel_token": "ups_standard",
 "carrier_account": 'CARRIER_TOKEN',
 "label_file_type": "PDF"
)
  .then(function(transaction) 
      return shippo.transaction.list(
        "rate": transaction.rate
      )
   )
  .then(function(mpsTransactions) 
    mpsTransactions.results.forEach(function(mpsTransaction)
        if(mpsTransaction.object_status == "SUCCESS") 
            console.log("Label URL: %s", mpsTransaction.label_url);
            console.log("Tracking Number: %s", mpsTransaction.tracking_number);
            console.log("E-Mail: %s", mpsTransaction.object_owner);
            console.log(mpsTransaction.object_status);
            res.status(200).send("Label can be found under: " + mpsTransaction.label_url);
         else 
            // hanlde error transactions
            console.log("Message: %s", mpsTransactions.messages);
        
    );
   )
  .catch(function (error) 
    // Deal with an error
    console.log("There was an error creating transaction : %s", err.detail);
    res.send("something happened :O")
  );

【讨论】:

以上是关于UnhandledPromiseRejectionWarning、Express.js 和 Node.js的主要内容,如果未能解决你的问题,请参考以下文章

[Unhandled promise rejection: TypeError: null is not an object (evaluating '_reactNativeImageCropPic

等待 - 捕获错误 - UnhandledPromiseRejectionWarning

批量删除如何工作?

7月工作知识总计:

未处理的承诺拒绝 |重启命令

未处理的承诺拒绝警告(Cordova Angular)