Axios处理错误

328

我正在尝试使用Axios更好地理解JavaScript Promise。我的目标是在Request.js中处理所有错误,并且只需从任何地方调用请求函数而无需使用catch()

在这个例子中,请求的响应将是400,JSON中包含错误消息。

这是我遇到的错误:

Uncaught (in promise) Error: Request failed with status code 400

我唯一找到的解决方法是在Somewhere.js中添加.catch(() => {}),但我正在努力避免这样做。这可能吗?

以下是代码:

Request.js

export function request(method, uri, body, headers) {
  let config = {
    method: method.toLowerCase(),
    url: uri,
    baseURL: API_URL,
    headers: { 'Authorization': 'Bearer ' + getToken() },
    validateStatus: function (status) {
      return status >= 200 && status < 400
    }
  }

  ...

  return axios(config).then(
    function (response) {
      return response.data
    }
  ).catch(
    function (error) {
      console.log('Show error notification!')
      return Promise.reject(error)
    }
  )
}

某个地方.js

export default class Somewhere extends React.Component {

  ...

  callSomeRequest() {
    request('DELETE', '/some/request').then(
      () => {
        console.log('Request successful!')
      }
    )
  }

  ...

}

你想要打破承诺链吗? - Niyoko
我不确定。这是否意味着我在调用请求函数时不必使用catch? - mignz
在您的应用程序中,一个不成功的状态代码是否在逻辑上是一个异常状态?您希望调用代码如何对此做出反应? - Benjamin Gruenbaum
1
如果您将错误沿着成功的路径发送,很有可能需要在某个更高的级别上测试它们以进行分支。我会说让成功成为成功,让错误成为错误,并相应地.catch()。 - Roamer-1888
15个回答

2

可以从任何地方调用请求函数,而无需使用catch()。

首先,虽然在一个地方处理大多数错误是一个好主意,但使用requests并不容易。一些错误(例如400个验证错误,如:“用户名已被使用”或“无效的电子邮件”)应该被传递。

因此,我们现在使用基于Promise的函数:

const baseRequest = async (method: string, url: string, data: ?{}) =>
  new Promise<{ data: any }>((resolve, reject) => {
    const requestConfig: any = {
      method,
      data,
      timeout: 10000,
      url,
      headers: {},
    };

    try {
      const response = await axios(requestConfig);
      // Request Succeeded!
      resolve(response);
    } catch (error) {
      // Request Failed!

      if (error.response) {
        // Request made and server responded
        reject(response);
      } else if (error.request) {
        // The request was made but no response was received
        reject(response);
      } else {
        // Something happened in setting up the request that triggered an Error
        reject(response);
      }
    }
  };

你可以像这样使用请求

try {
  response = await baseRequest('GET', 'https://myApi.com/path/to/endpoint')
} catch (error) {
  // either handle errors or don't
}

抱歉挑剔一下,但有两件事情:如果你真的想使用async,请将它移到你的promise resolve/reject函数前面。或者最好不要使用promise(因为你正在用一个async装饰器包装baseRequest),只需继续使用try/catch和错误类型分支,并使用return而不是resolve。其次,我喜欢测试缺少服务器响应的方法!但是当axios超时时,它会抛出异常并被视为服务器没有返回响应吗?还是这些情况是相同的? - airtonix
感谢您的建议,airtonix。这个函数很旧了,我很高兴能改进代码。在这个函数中混合使用async/await和Promises并不理想。您能否编辑我的评论以反映这些更改?关于您的问题,据我所知,axios在代码的catch部分都会处理。我会手动将超时设置得非常短,以测试超时错误处理。您所说的“缺席服务器”是指404错误吗?还是没有网络错误?所有这些都在catch块中处理,因此请尝试自己触发它们进行测试。 - David Schumann

0
如果我理解正确的话,您想要一种全局处理程序,这样您就不必为每个请求附加一个catch处理程序。有一个名为unhandledrejection的窗口事件可以实现这一点。
您可以在官方文档中了解更多关于此事件的信息:https://developer.mozilla.org/en-US/docs/Web/API/Window/unhandledrejection_event 以下是如何为此事件附加侦听器的方法:
window.addEventListener('unhandledrejection', (event) => {
  // Handle errors here...
});

0
let response;
await axios({ method, url, data: body, headers })
.then(data => { response = data })
.catch(error => { response = error.response; });

在这个response对象中,您将获得所有类型的响应,无需担心axios错误,您可以根据response.status处理事情。


0

我曾经遇到过这样的情况,即无法访问应用程序的后端,因此使用了一个工具来验证字段,返回类似于response.data的内容:

"Error: Username 'UsuarioTeste' is already taken.."

由于这是一个标准消息,我需要对其进行调整以向用户呈现,我使用了以下过程:

.catch((error) => {
      const errosCadastro = error.response.data;
      const listaErros = errosCadastro.split("\n");
      listaErros.map(erro => {
        if (erro.includes("Error")) {
          const start = erro.indexOf(":") + 2;
          const end = erro.indexOf("'", start) - 1;
          const fieldName = erro.substring(start, end);
          const ErroCampo =
            fieldName == "Username" ? `Já existe um usuário cadastrado com o nome: <span style="font-weight: bold;"> ${this.name}</span>. <br>`
              : fieldName == "Email" ? `Já existe um usuário cadastrado com o email: <span style="font-weight: bold;"> ${this.email}</span>. <br>`
                : fieldName == "registro" ? `Já existe um usuário cadastrado com o registro: <span style="font-weight: bold;"> ${this.record}</span>. <br>`
                  : "";

          errorMessage = errorMessage.concat(ErroCampo);
        }
      })

0
创建axios实例: ``` export const api = axios.create({ baseURL: '/api' }); ```
- 这是用于响应的中间件
api.interceptors.response.use(
  (res) => res,
  (err) => {
    if (err.response && err.response.status >= 500) {
      // Handling for server errors (status code >= 500)
      const { response } = err;
      const message = createErrorMessage(err);

      if (message) {
        // Return the error or additional information for further handling
        // you could populate the store here if you have a global store 
        return {
          error: {
            contentType: response.headers['Content-Type'] || response.headers['content-type'],
            message: createErrorMessage(err)
          }
        };
      }
    }
    // this will be returned if the error status is less than 500
    // this will be caught in the try/catch block when axios fetching executed. so you could catch and handle in there
    return Promise.reject(err); // Rejection if error doesn't meet conditions
  }
);

- 这是上面使用的实用函数
export const createErrorMessage = (error: unknown) => {
    // When Axios encounters an error during an HTTP request or response handling, it creates a specific Axios error object
    if (axios.isAxiosError(error)) {
        const apiError = error.response?.data;
        if (typeof apiError === 'string' && (apiError as string).length > 0) {
            return apiError;
        }
        return apiError?.message || apiError?.error || error.message;
    }
    // Network errors
    // timeout errors
    // CORS errors
    if (error instanceof Error) {
        return error.message;
    }
    if (
        error &&
        typeof error === 'object' &&
        'message' in error &&
        typeof error.message === 'string'
    ) {
        return error.message;
    }

    return 'Generic error message';
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接