代码之家  ›  专栏  ›  技术社区  ›  grazdev

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

  •  1
  • grazdev  · 技术社区  · 5 年前

    我正在创建一个由节点(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 是一个helper函数,其外观如下:

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

    当请求成功时以及当我得到 404 500 错误。但假设我故意使用错误的端点:

    const apiBase = 'http://www.example.com'
    
    export default {
        news: wrongApiBase + '/news/'
        // other endpoints
    }
    

    在这种情况下,节点会给我以下错误,因为 wrongApiBase 未定义:

    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 对账单 异步请求 但是我不知道我应该从中得到什么,然后我可以用在 获取首字母道具 . 我试着回来了 false 但是没有什么变化,页面就是不加载。

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

    +++更新+++

    事实证明,我产生的错误有问题。就像我说的,我用错了变量名( wrongBaseApi )触发一个错误,导致节点从不为页面服务。事后看来,这是有道理的,因为它是节点代码错误,而不是传入请求错误。

    通过使用正确的变量但为其分配错误的值(实际错误的API基,例如 http://dahfjkdahfds.com 这不是节点错误,而是请求错误),我可以使用@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 } 
        }
    }
    
    2 回复  |  直到 5 年前
        1
  •  2
  •   iKoala    5 年前

    我认为您必须处理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 };
      }
    }
    
        2
  •  0
  •   Mr.Throg    5 年前

    不是很好的方法,但是我们可以通过在根节点上添加事件侦听器来实现

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

    像这样。

        3
  •  0
  •   NullDev Kevin Fisher    5 年前

    既然是nodejs,我会用 process.on() (而不是 window.addEventListener() )与 unhandledRejection 事件:

    process.on("unhandledRejection", (err, promise) => {
        console.log(`Unhandled rejection (promise: ${promise}, reason: ${err})`);
    });
    
        4
  •  0
  •   DEVCNN    5 年前

    假设您的getInitialProps调用AsyncReq,而AsyncReq又调用ThrowerRor方法。现在,如果throwerror方法抛出了一个错误,您可以使用getInitialProps中的catch块来捕获它。因此,应该始终在启动函数链的函数中放置一个catch块。为了更好地诊断错误,应该在每个函数中放置catch块。但作为一般规则,必须在调用的第一个函数中捕获块。

    getInitialProps = async function( { query: { slug } } ) {
    try{
    const news = await asyncReq( 'http://localhost:3000/' + slug )
    return { news, error: news.status }
    }
    catch(err){
    console.log('err:', err);
    }
    }
    
    const throwError = () => {
    throw 'New Error'
    }
    
    const asyncReq = endpoint => {
    throwError();
    return 
        fetch( endpoint )
        .then( res => { return res.ok ? res.json() : res } )
    }