Skip to content

try-catch的 catch 里面务必输出error.message,否则 try 内的代码如果报错,我们是找不到错误原因的!非常坑!

error.message其实就是正常的浏览器输出的错误中的 message!

例子:

jsx
//captcha logic
      onCaptchaShow(async (ticket, randstr) => {
        try {
          const res = await passwordLogin(formData.email, formData.password, ticket, randstr, roleLogin); //real logic
          const newToken = res.data.token; //real logic
          const role = res.data.role;
          let getInfoFun = getUserInfo;
          if (role === "member") {
            getInfoFun = getUserInfo;
          } else if (role === "trainer") {
            getInfoFun = getTrainerInfo;
          } else if (role === "admin") {
            getInfoFun = getAdminInfo;
          }
          // let getInfoFun = getUserInfo; // test data
          // const newToken = "123456"; // test data
          await setToken(newToken, role, getInfoFun);
          showSnackbar({ message: "Login Successful!", severity: "success" });
          console.log("Login Successful!", role);
          //base the role to redirect to the right page
          // navigate(`/${role}`); // don't need this logic
        } catch (error) {
          if (error) {
            //要做错误处理,不然 try-catch之后直接就没办法看到报错了,导致找不到问题所在 ——> 关键点
            showSnackbar({ message: error.message || "Login failed. Please try again.", severity: "error" });
          }
        }
      },

也就是说不能只写这个 "Login failed. Please try again." 这种固定内容的错误提示!不全面,很烂的代码!

一开始我们把roleLogin写成 role,造成变量的重复定义,但是由于被catch了,所以怎么都找不到错误原因!!!

前端错误处理的总结

接口的错误在公共 axios 里面处理

根据后端状态码(http 是正确的情况下,后端的自定义状态码),和后端给的错误信息 msg 进行输出

js
service.interceptors.response.use(
    (response) => {
      const res = response?.data;
      //Normally, the exception code returned by the back end will still go here
      if (res?.code !== 200) {
        console.log("response:", res);
        console.log("If code is not 200, an error is reported by default");
        return Promise.reject({ response }); // Force the error handling logic
      } else {
        //Direct return response.data
        return res;
      }
    },
    (error) => {
      // From code! ==200 logic jump over
      const res = error?.response;
      console.log(res);
      // As long as you set code then the back end must set message
      if (res?.data?.message && res?.data?.code) {
        // error.message = res.data.message;
        errorNotifier.showError(res.data.message);
        return Promise.reject();
      } else if (error?.message) { //Otherwise, let the page handle it
        console.log("error.message:", error?.message, error);
        // errorNotifier.showError(error?.message);
        return Promise.reject(error);
      } else { //Otherwise, let the page handle it
        console.log("error:", error);
        return Promise.reject(error);
      }
    }
  );

页面内部的错误在 catch 里面处理(或者后端没给错误信息 msg)

js
try {
    const res = await passwordLogin(formData.email, formData.password, ticket, randstr, roleLogin); //real logic
    const newToken = res.data.token; //real logic
    const role = res.data.role;
    let getInfoFun = getUserInfo;
    if (role === "member") {
      getInfoFun = getUserInfo;
    } else if (role === "trainer") {
      getInfoFun = getTrainerInfo;
    } else if (role === "admin") {
      getInfoFun = getAdminInfo;
    }
    // let getInfoFun = getUserInfo; // test data
    // const newToken = "123456"; // test data
    await setToken(newToken, role, getInfoFun);
    showSnackbar({ message: "Login Successful!", severity: "success" });
    console.log("Login Successful!", role);
    //base the role to redirect to the right page
    // navigate(`/${role}`); // don't need this logic
  } catch (error) {
    if (error) {
      //要做错误处理,不然 try-catch之后直接就没办法看到报错了,导致找不到问题所在 ——> 关键点
      showSnackbar({ message: error.message || "Login failed. Please try again.", severity: "error" });
    }
  }

更正:之前的思路是错误的!

==因为我们实际上发现上面return Promise.reject({ response });之后也走不到下面的error处理,下面的error只能处理真正的请求错误,而不是后端构造的错误信息(后端构造的统一视为正确返回),错误的返回其实只存在 axios 错误一种可能(比如服务器连接不上,没有网络等)==

所以统一的错误处理必须要在上面!

下面才是正确的统一的大一统写法:但不是最终版,我们还要仔细分析一下

js
service.interceptors.response.use(
    (response) => {
      const res = response?.data;
      if (res?.code !== 200) {
        console.log("response:", res, { response });
        console.log("If code is not 200, an error is reported by default");
        // return Promise.reject({ response }); //这样行不通,走不到下面那里
        // return Promise.reject(new Error(res.message || "Error")); //这样不利于我们公共弹窗报错
        // 后端只要设置了code 就应该一定设置了 message
        if (res?.message && res?.code) {
          errorNotifier.showError(res.message);
          return Promise.reject(); //这个地方必须要返回,否则默认会返回 resolve 的,页面 try-catch会不起作用,不知道代码出了错误!会导致页面中代码逻辑意外向下执行!//而且页面必须写 try-catch,否则页面会直接产生意外报错,不太好
        } else { //如果没设置 message,那就让页面处理
          console.log("error:", res);
          return Promise.reject(new Error(""));
        }
      } else {
        //Direct return response.data
        return res;
      }
    },
    (error) => {
      // 这里只处理 axios 的 error
      // errorNotifier.showError(error?.message || "Error"); //但是这种错误最好是让页面自己处理(因为我们不知道每个页面错误的时候应该说什么具体的东西,比如登录页面要说:登录错误请重试!)
      return Promise.reject(new Error(error?.message));
    }
  );

这是 axios 错误的示例:

image-20250301194400676

页面里面处理错误:

1.正常情况下,如果后端确保每个接口都在错误情况的时候正确返回了错误的 msg 和code 了,那么其实我们页面中没有必要做任何处理!

因为页面上报错的唯一可能就是我们的页面 js 代码报错了,而请求的错误都在 axios封装里面集中处理完了!

所以页面根本没必要进行任何的错误处理,但是try-catch还是必须要写的!不然代码走不下去!

js
const handleGetStatisticData = async () => {
  if (!selectionRange.startDate || !selectionRange.endDate) return;

  setLoading(true);
  try {
    await getData();
  } catch (error) {
    // console.log(error); //这里一定是 undefined
  }
  // await getData(); //不写 try-catch不行,不然代码走不下去!
  setLoading(false);
};

==注意:我们在 axios 里面处理错误的时候必须要返回 Project.reject,否则默认会返回 resolve 的,这时候如果页面写了 try-catch会不起作用,走不到 catch,不知道代码出了错误!会导致页面中代码逻辑意外向下执行!==

==而且页面不能不写 try-catch,必须写 try-catch,否则页面会直接产生意外报错,不太好!==

由于我们不能保证后端一定会处理每个错误(都写了 message)!有的还是我们自己处理会比较好!

所以下面是最好的写法

2.页面里面再次进行错误处理

这样error可能是 js 代码错误,也可能是后端没有设置message 时候的错误,我们在页面里面再进行弹窗!

js
try {
  const res = await passwordLogin(formData.email, formData.password, ticket, randstr, roleLogin); 
} catch (error) {
  if (error) {
    showSnackbar({ message: error.message || "Login failed. Please try again.", severity: "error" });
  }
}

==注意:必须判断 error 是否存在,因为showError处理完的,还是会返回到页面中,会走到catch这里,走到了 catch 的 如果 error 存在,那么就是需要在页面里面处理 error!(可能是 js 代码错误,也可能是后端没有设置message 时候的错误)==

总结最终的 axios 封装错误处理

封装:

js
service.interceptors.response.use(
    (response) => {
      const res = response?.data;
      if (res?.code !== 200) {
        console.log("response:", res, { response });
        console.log("If code is not 200, an error is reported by default");
        // 后端只要设置了code 就应该一定设置了 message
        if (res?.message && res?.code) {
          errorNotifier.showError(res.message);
          return Promise.reject(); //必须返回Promise.reject
        } else { //如果没设置 message,那就让页面处理,但是这里 message 我们给空的
          console.log("error:", res);
          return Promise.reject(new Error(""));
        }
      } else {
        return res;
      }
    },
    (error) => {
      // 这里只处理 axios 的 error
      errorNotifier.showError(error?.message || "Error");
      return Promise.reject(); //必须返回Promise.reject
    }
  );

页面:

重要的接口:需要处理后端没设置 message的情况的(但是这个情况一般不存在)——> ==在公司写项目的时候最好这么写,后端没设置 message的情况和 js 代码报错的情况都能弹窗出来==

js
try {
  const res = await passwordLogin(formData.email, formData.password, ticket, randstr, roleLogin); 
} catch (error) {
  if(error){
    showSnackbar({ message: error.message || "Login failed. Please try again.", severity: "error" });
  }
}

简单的接口:不需要弹窗的

js
try {
  const res = await passwordLogin(formData.email, formData.password, ticket, randstr, roleLogin); 
} catch (error) {
  console.error(error?.message);
}

直接这样写,就算是后端没设置 message 我们也不管了(有报错可以在控制台看),只需要把js 代码报错console出来就行!