【问题标题】:Handling Axios error in React在 React 中处理 Axios 错误
【发布时间】:2018-04-10 20:30:39
【问题描述】:

我有一个调用函数 getAllPeople 的 React 组件:

componentDidMount() {
   getAllPeople().then(response => {
      this.setState(() => ({ people: response.data }));
    });
  } 

getAllPeople 在我的api 模块中:

export function getAllPeople() {
  return axios
    .get("/api/getAllPeople")
    .then(response => {
      return response.data;
    })
    .catch(error => {
      return error;
    });
}

我认为这是一个非常基本的问题,但假设我想处理我的根组件中的错误(在我的componentDidMount 方法中),而不是在api 函数中,这个根组件如何知道是否我axios 调用返回错误? IE。处理来自 axios 承诺的错误的最佳方法是什么?

【问题讨论】:

    标签: reactjs error-handling axios


    【解决方案1】:

    使用 Promise catch 方法处理 API 错误的更好方法*

    axios.get(people)
        .then((response) => {
            // Success
        })
        .catch((error) => {
            // Error
            if (error.response) {
                // The request was made and the server responded with a status code
                // that falls out of the range of 2xx
                // console.log(error.response.data);
                // console.log(error.response.status);
                // console.log(error.response.headers);
            } else if (error.request) {
                // The request was made but no response was received
                // `error.request` is an instance of XMLHttpRequest in the 
                // browser and an instance of
                // http.ClientRequest in node.js
                console.log(error.request);
            } else {
                // Something happened in setting up the request that triggered an Error
                console.log('Error', error.message);
            }
            console.log(error.config);
        });
    

    【讨论】:

      【解决方案2】:

      getAllPeople 函数已从您的axios 调用返回数据或错误消息。因此,在componentDidMount 中,您需要检查对getAllPeople 的调用的返回值,以确定返回的是错误还是有效数据。

      componentDidMount() {
         getAllPeople().then(response => {
            if(response!=error) //error is the error object you can get from the axios call
               this.setState(() => ({ people: response}));
            else { // your error handling goes here
             }
          });
        } 
      

      如果你想从你的 api 返回一个 promise,你不应该在 api 中解析你的 axios 调用返回的 promise。相反,您可以执行以下操作:

      export function getAllPeople() {
        return axios.get("/api/getAllPeople");
      }
      

      然后你可以在componentDidMount解决。

      componentDidMount() {
         getAllPeople()
         .then(response => {          
               this.setState(() => ({ people: response.data}));
           })
         .catch(error => { 
               // your error handling goes here
           }
        } 
      

      【讨论】:

      • 我还没有按照你的建议从我的 api 返回axios.get(...) 吗?
      • 用代码编辑了我的答案以澄清我的意思。
      【解决方案3】:

      我的建议是使用 React 的尖端功能。 Error Boundaries

      这是 Dan Abramov 使用此功能的example。 在这种情况下,您可以使用此错误边界组件包装您的组件。 在 axios 中捕捉错误的特别之处在于可以使用 interceptors 用于捕获 API 错误。 您的错误边界组件可能看起来像

      import React, { Component } from 'react';
      
      const errorHandler = (WrappedComponent, axios) => {
        return class EH extends Component {
          state = {
            error: null
          };
      
          componentDidMount() {
            // Set axios interceptors
            this.requestInterceptor = axios.interceptors.request.use(req => {
              this.setState({ error: null });
              return req;
            });
      
            this.responseInterceptor = axios.interceptors.response.use(
              res => res,
              error => {
                alert('Error happened');
                this.setState({ error });
              }
            );
          }
      
          componentWillUnmount() {
            // Remove handlers, so Garbage Collector will get rid of if WrappedComponent will be removed 
            axios.interceptors.request.eject(this.requestInterceptor);
            axios.interceptors.response.eject(this.responseInterceptor);
          }
      
          render() {
            let renderSection = this.state.error ? <div>Error</div> : <WrappedComponent {...this.props} />
            return renderSection;
          }
        };
      };
      
      export default errorHandler;
      

      然后,你可以用它来包装你的根组件传递 axios 实例

      errorHandler(Checkout, api)
      

      因此,您根本不需要考虑组件内部的错误。

      【讨论】:

      • 这似乎是一个很好的例子,但我没有得到WrappedComponent ,它是什么?另外,把errorHandler(Checkout, api)放在哪里?
      • 我的响应拦截器没有检测到500的错误
      • 嗨@yevhenii,只是好奇该API是否在Checkout的componentDidMount上。如果 api 没有暴露给它,errorHandler 将如何捕获它。有什么策略吗?
      • @TOS API 是什么意思? Axios 正在执行所有调用,并且每个调用都有拦截器。您在 componentDidMount 中看到的函数不是 API 调用,它更像是为每个调用设置中间件。是的,你必须在里面传递 axios 的实例
      【解决方案4】:

      您可以在将其设置为state 之前检查响应。类似的东西

      componentDidMount() {
         getAllPeople().then(response => {
             // check if its actual response or error
              if(error) this.setState(() => ({ error: response }));
              else this.setState(() => ({ people: response}));
          });
        }
      

      它依赖于axios 将返回不同的对象来表示成功和失败。

      【讨论】:

        【解决方案5】:

        Yevhenii Herasymchuk 的解决方案非常接近我的需要,但是我的目标是使用功能组件实现,以便我可以使用 Hooks 和 Redux。

        首先我创建了一个包装器:

        export const http = Axios.create({
            baseURL: "/api",
            timeout: 30000,
        });
        
        function ErrorHandler(props) {
        
        useEffect(() => {
            //Request interceptor
            http.interceptors.request.use(function (request) {
                // Do something here with Hooks or something else
                return request;
            });
        
            //Response interceptor
            http.interceptors.response.use(function (response) {
                if (response.status === 400) {
                    // Do something here with Hooks or something else
                    return response;
                }
                return response;
            });
        }, []);
        
        return props.children;
        }
        
        export default ErrorHandler;
        

        然后我包装了我需要检查 axios 行为方式的项目部分。

        <ErrorHandler>
          <MainPage/>
        </ErrorHandler>
        

        最后,我将 axios 实例 (http) 导入到项目中任何需要它的地方。

        希望它能帮助任何希望采用不同方法的人。

        【讨论】:

          猜你喜欢
          • 2018-10-02
          • 2018-03-09
          • 2020-11-19
          • 1970-01-01
          • 2020-10-12
          • 1970-01-01
          • 2018-02-14
          相关资源
          最近更新 更多