如何处理Node错误“未处理的承诺拒绝”,以便无论如何都可以加载页面?

时间:2019-03-20 08:21:01

标签: javascript node.js promise

我正在创建一个由Node(Express)服务器提供服务的Next.js应用程序,该服务器通过对API的请求提取数据。我将请求端点保存在单独的api文件中:

const apiBase = 'http://www.example.com'

export default {
    news: apiBase + '/news/'
    // other endpoints
}

然后我在getInitialProps中进行请求,并根据请求是否给出错误进行条件渲染:

static async getInitialProps( { query: { slug } } ) {
    const news = await asyncReq( api.news + slug )
    return { news, error: news.status }
}

render() {
    return this.props.error ? <Error /> : <News />
}

asyncReq是一个类似于以下内容的辅助函数:

export const asyncReq = endpoint => {
    return 
        fetch( endpoint )
        .then( res => { return res.ok ? res.json() : res } )
}

当请求成功以及遇到404500错误时,这一切都很好。但是,假设我故意使用了错误的端点:

const apiBase = 'http://www.example.com'

export default {
    news: wrongApiBase + '/news/'
    // other endpoints
}

在这种情况下,由于wrongApiBase未定义,Node给我以下错误:

UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 498)

这是应该执行的操作,但是错误导致页面永不加载。我应该怎么处理错误?我的想法是将一个catch语句链接到asyncReq,但是我不确定应该从中返回什么,然后可以在getInitialProps中使用。我尝试返回false,但没有任何变化,只是页面未加载。

export const asyncReq = endpoint => {
    return 
        fetch( endpoint )
        .then( res => { return res.ok ? res.json() : res } )
        .catch( err => { // What should I return here? )
}

+++更新+++

事实证明,我所产生的错误存在问题。就像我说的那样,我使用错误的变量名(wrongBaseApi)来触发错误,这导致Node永远不会为页面提供服务。事后看来,这是有道理的,因为这是节点代码而不是传入请求的错误。

通过使用正确的变量但为其分配了错误的值(实际上是错误的API库,例如http://dahfjkdahfds.com,这不是Node错误,而是请求错误),我能够使使用@iKoala和@DEVCNN工作提供的try / catch块的解决方案。所以我的代码变成了:

static async getInitialProps( { query: { slug } } ) {
    const news = await asyncReq( api.news + slug )
    return { news }
}

render() {
    // this.props.news.data
    // this.props.news.error
}

export async function asyncReq( endpoint ) {
    try {
        const res = await fetch( endpoint )
        return { 
            data: res.ok ? await res.json().then( val => { return val } ) : null,
            error: res.ok ? false : res.status
        } 
    } catch( error ) {
        return { error } 
    }
}

4 个答案:

答案 0 :(得分:2)

我认为您必须处理从asyncReq引发的错误:

static async getInitialProps( { query: { slug } } ) {
  try {
    const news = await asyncReq( api.news + slug )
    return { news, error: news.status }
  } catch (err) {
    // any error, including http error 40x and 50x
    return { news: null, error: err };
  }
}

答案 1 :(得分:0)

这不是一个好方法,但是我们可以通过在根节点上添加事件监听器来实现

 window.addEventListener('unhandledrejection', rj => {
      this.setState({hasError: true})
    })

类似的东西。

答案 2 :(得分:0)

由于它是NodeJS,因此我将在process.on()事件中使用window.addEventListener()(而不是unhandledRejection):

process.on("unhandledRejection", (err, promise) => {
    console.log(`Unhandled rejection (promise: ${promise}, reason: ${err})`);
});

答案 3 :(得分:0)

比方说,您的getInitialProps调用asyncReq,后者又调用throwError方法。现在,如果throwError方法引发错误,则可以使用getInitialProps中的catch块来捕获它。因此,您应该始终在启动函数链的函数中放置catch块。为了更好地诊断错误,应在每个功能中放置catch块。但通常,在您调用的第一个函数中必须具有catch块。

var orders = allPendingOrdersCopy.Where(o => o.OrderDetails.Any())