reactjs - 使用 Axios 在反应中进行错误处理的最佳方法是什么?
问题描述
我正在开发一个 React 应用程序。无论是 Angular/React/Vue 项目,我每次都面临的问题是 AJAX 请求期间的错误处理(可以使用 Axios 或任何其他 AJAX 库进行)
我在这里找到的大多数答案都只是在console.log(error)
ortry catch
方法Promise.reject()
中进行。现实世界的应用程序不是这样工作的。
我想迎合所有可能的错误,并根据错误的类型向用户显示适当的消息。例如,错误可能是:
- 来自 API 的验证错误。
- 网络失败。
- 电子邮件/密码等一般错误不正确。
- 在 GET 请求期间需要来自 API 的一些数据但由于错误而失败的表单。现在我将留下的是一个无法继续前进的死亡形式。
- 任何其他可能引发错误的原因。
我怎样才能知道所有可能的错误情况?重要的是,制作它们以查看我的应用程序如何响应它们中的每一个。
由于我也在开发 API,请让我知道我应该如何将错误发送回前端,以便它可以适当地处理它们。
目前,我的实现是(这不是很好的 IMO):
import React from "react";
import Link from "../../components/AppLink/AppLink";
import AppTextField from "../../components/FormComponents/AppTextField";
import styles from "../../styles/Auth.module.css";
import { Box, Button, Grid, Hidden, InputAdornment, Typography, Collapse } from "@material-ui/core";
import { Alert, AlertTitle } from '@material-ui/lab';
import EmailSvgIcon from "../../components/Icons/EmailSvgIcon";
import LockSvgIcon from "../../components/Icons/LockSvgIcon";
import LockOpenIcon from '@material-ui/icons/LockOpen';
import { ROUTE_FORGOT_PASSWORD, ROUTE_REGISTER } from "../../utils/RoutesList";
import AuthBanner from "../../components/AuthBanner/AuthBanner";
import useIsMobile from "../../hooks/useIsMobile";
import * as yup from 'yup';
import axios from '../../axiosConfig';
import CircularProgress from '@material-ui/core/CircularProgress';
import { useState } from "react";
import { AlertProps } from "@material-ui/lab";
import { mapApiErrorsToHookForm } from "../../utils/Form";
import { AxiosError } from "axios";
import { useForm, FormProvider } from "react-hook-form";
import { yupResolver } from '@hookform/resolvers/yup';
interface FormValues
{
email: string;
password: string;
}
interface AlertState
{
severity : AlertProps["severity"];
title : string;
message : string;
show : boolean;
}
const validationSchema = yup.object().shape({
email: yup.string()
.required("Please enter your email")
.email("Please enter a valid email address"),
password: yup.string().required("Please enter your password"),
});
const LoginPage = () =>
{
const formMethods = useForm <FormValues>({
resolver: yupResolver(validationSchema)
});
const { isSubmitting } = formMethods.formState;
const isMobile = useIsMobile();
const [alert, setAlert] = useState <AlertState>({
severity : undefined,
title : "",
message : "",
show : false,
});
const onSubmit = async (formValues: any) =>
{
try
{
const response = await axios.post("auth/user/login", formValues);
}
catch (error)
{
const exception: AxiosError = error;
let title = "Error", message: string;
if (exception.response && exception.response.status === 400)
{
message = exception.response.data.message;
switch (exception.response.data.errorType)
{
case "VALIDATION_ERROR":
title = "Incorrect input";
let errors = mapApiErrorsToHookForm(exception.response.data.errors)
for (let field in errors)
{
formMethods.setError(field as keyof FormValues, {
type: "validation",
message: errors[field]
});
}
break;
case "ACCOUNT_NOT_FOUND":
title = "Account not found";
break;
}
}
else
{
message = exception.message;
}
setAlert({
title,
message,
severity: "error",
show: true
});
}
}
return (
<>
<Grid
item
container
xs={12}
sm={4}
direction="column"
justify="space-between"
className={styles.bannerGrid}>
<AuthBanner
image="/images/auth/login_banner.jpg"
title="Tip"
description="The search for housing on this site is 10 times faster"
/>
</Grid>
<Grid item container sm={8} className={styles.contentWrapper}>
<Box display="flex" flexDirection="column" flex={1} paddingX={2} paddingY={2}>
<Hidden only="xs">
<Box textAlign="right">
<Link
underline="none"
href={ROUTE_REGISTER}
color="textPrimary"
className={styles.topLink}>
Register
</Link>
</Box>
</Hidden>
<Box
display="flex"
flexDirection="column"
justifyContent="center"
flex={1}
maxWidth={500}>
<Box marginBottom={3}>
<Box marginBottom={1.5}>
<Typography variant="h4" className={styles.formTitle}>Login</Typography>
</Box>
<Typography variant="body1" color="textSecondary">Welcome back!</Typography>
</Box>
<FormProvider {...formMethods}>
<form onSubmit={formMethods.handleSubmit(onSubmit)}>
<Collapse in={alert.show && !isSubmitting}>
<Box marginBottom={3}>
<Alert
severity={alert.severity}
onClose={() => setAlert({...alert, show: false})}>
<AlertTitle>{alert.title}</AlertTitle>
{alert.message}
</Alert>
</Box>
</Collapse>
<Box marginBottom={2}>
<AppTextField
name="email"
type="email"
label="Email"
variant="outlined"
fullWidth
InputProps={{
endAdornment: (
<InputAdornment position="end">
<EmailSvgIcon fontSize="small" />
</InputAdornment>
),
}}
/>
</Box>
<Box marginBottom={2}>
<AppTextField
name="password"
type="password"
label="Password"
variant="outlined"
fullWidth
InputProps={{
endAdornment: (
<InputAdornment position="end">
<LockSvgIcon fontSize="small" />
</InputAdornment>
),
}}
/>
</Box>
<Grid container spacing={2}>
<Grid
item xs={12}
sm={6}>
<Button
type="submit"
variant="contained"
color="primary"
size="large"
endIcon={
isSubmitting
? <CircularProgress color="secondary" size={18} />
: <LockOpenIcon />
}
fullWidth={isMobile}
disabled={isSubmitting}>
Login
</Button>
</Grid>
<Grid
item
container
xs={12}
sm={6}
alignItems="center"
justify={isMobile ? "center" : "flex-end"}>
<Link
href={ROUTE_FORGOT_PASSWORD}
color="primary"
className={styles.formLink}>
Forgot Password?
</Link>
</Grid>
</Grid>
</form>
</FormProvider>
</Box>
</Box>
</Grid>
</>
);
}
export default LoginPage;
对于这个特定的表单,我errorType
从 API 发送并基于它,我设置了相应的警报标题和消息,但是我需要为每个表单都这样做吗?
我知道拦截器,但它无法在每个错误字段下显示验证消息,因为formMethods
它无法在其上下文中显示。
请提供带有示例的详细答案,以便我对此有很好的理解。另外,不要忘记解释如何处理所有可能的错误情况并处理它们。
提前致谢 :)
解决方案
您可以创建一个Axios实例,并像这样全局处理一些错误
const axiosInstance = Axios.create({
baseURL: apiEndpoint,
headers: {
'Content-Type': 'application/json',
},
});
axiosInstance.interceptors.response.use(undefined, error => {
const statusCode = error.response ? error.response.status : null;
if (statusCode === 401) {
// logout user
}
if (statusCode >= 500) {
// show server error
}
if (statusCode === 400) {
// show bad request error
}
return Promise.reject(error);
});
然后,如果您需要,您还可以在组件级别进行处理。
推荐阅读
- codeigniter-4 - Codeigniter 4 - 从另一个控制器调用方法
- python - 用频率替换列值
- ios - Xamarin - 提交的应用程序 - 细化过程中发生错误
- c++ - 如何正确结束线程?
- ios - React Native Launch/Splash Screen 最佳实践?
- c# - 设置 HttpWebRequest 标头
- android - 如何停止显示 oneSignal 通知 UI?
- c# - IAccessible 的 accDoDefaultAction 被 ROLE_SYSTEM_PUSHBUTTON 忽略
- excel - Excel:尝试获取公式以基于跨多个表的单元格查找来填充值
- ruby-on-rails - React Rails 组件将无法工作 Rails 5.2.4