[React]麻烦大家帮我看看代码,为什么 axios 的拦截器没能正常捕获到错误?

2019-12-27 22:39:34 +08:00
 Danswerme

代码在这里 https://codesandbox.io/s/vigilant-napier-wzd4e

为什么拦截器里未能正常捕获 HomePage 组件里的 401 错误呢?将函数放入 setTimeout 里执行时又可以捕获到错误,麻烦大家帮我看看问题出在哪里。

3354 次点击
所在节点    React
14 条回复
manami
2019-12-28 09:07:17 +08:00
手机刷不出来代码。会不会是 axios 是异步请求导致的。“将函数放入 setTimeout 里执行时又可以捕获到错误”,setTimeout 严格意义上不是异步。
Danswerme
2019-12-28 09:22:51 +08:00
import React, { useContext, useEffect } from "react";
import axios from "axios";

export const AjaxContext = React.createContext();
export const useAjax = () => useContext(AjaxContext);

const instance = axios.create({
timeout: 5000
});

export function AjaxProvider({ children }) {
useEffect(() => {
const onReq = config => {
config.headers["Authorization"] = localStorage.getItem("token");
return config;
};
const onErr = err => Promise.reject(err);

const flag = instance.interceptors.request.use(onReq, onErr);
return () => instance.interceptors.request.eject(flag);
});

useEffect(() => {
const onRes = res => res;
const onErr = err => {
if (err.response) {
const { status } = err.response;
if (status === 401) {
console.log("捕获到了!");
}
}

return Promise.reject(err);
};

const flag = instance.interceptors.response.use(onRes, onErr);
return () => instance.interceptors.response.eject(flag);
});

const ajax = {
get: path => instance.get(path),
post: (path, data) => instance.post(path, data),
put: (path, data) => instance.put(path, data),
delete: path => instance.delete(path)
};

return <AjaxContext.Provider value={ajax} children={children} />;
}
Danswerme
2019-12-28 09:23:13 +08:00
import React, { useEffect, Component } from "react";
import { useAjax, AjaxContext } from "./Ajax";

export function HomePage() {
const ajax = useAjax();

async function testToken() {
try {
const result = await ajax.get(
"https://api.youneedabudget.com/v1/budgets"
);
} catch (err) {
console.log(err);
}
}

useEffect(() => {
// testToken();

setTimeout(testToken);
});

return (
<div>
App
<button onClick={testToken}>GoGoGo</button>
</div>
);
}
Danswerme
2019-12-28 09:23:31 +08:00
import React from "react";
import ReactDOM from "react-dom";
import { AjaxProvider } from "./Ajax";
import { HomePage } from "./HomePage";

function App() {
return (
<AjaxProvider>
<HomePage />
</AjaxProvider>
);
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Danswerme
2019-12-28 09:26:31 +08:00
@manami 代码我贴在楼上啦,你看看。 如果用按钮点击执行这个 ajax 函数时,axios 拦截器可以正常捕获到错误,而在组件刚挂载完时执行这个 ajax 函数就无法捕获到,不知道是哪里的问题。
manami
2019-12-28 09:43:06 +08:00
@Danswerme 看完代码懵逼。axios 还有拦截器这种用法,期待其他专业前端的回答,学习学习
ztmqg
2019-12-28 09:57:27 +08:00
@manami 是的,基本上都会封装一下,后续省事
Danswerme
2019-12-28 09:58:16 +08:00
@manami 我也是菜鸟,以前都是直接将 axios 封装成一个 http 模块,然后在用到的地方引入。这次在 react-china http://react-china.org/t/topic/32941 看到了将 axios 直接放在 context 里的方法,特地用的试了下,结果就卡在这里了
miniwade514
2019-12-28 09:58:32 +08:00
在手机上艰难地看了很久,越看越懵逼。发请求这种事情为什么也要用 hooks,跟 react 组件的生命周期挂上钩,排查问题都不方便啊。
你说的能捕获,是指执行了 console.log("捕获到了") 那一行?
simonv3ex
2019-12-28 10:00:47 +08:00
贼 jer 卡
const result = await ajax.get(
"https://api.youneedabudget.com/v1/budgets"
).catch(err=>{
alert(err);
});
Danswerme
2019-12-28 10:13:55 +08:00
@miniwade514 是的,我指的捕获就是那一行。我是将用户 token 保存在 localStorage 里,用户信息、是否登录等状态放在 redux 里,每次第一次打开页面时会发请求去验证 token 是否合法,如果合法就将服务器返回的用户信息放进 redux 里,并将是否登录设置为 true。

不合法时服务器返回 401 就发起一个 dispatch,将是否登录设置为 false,下面的 PrivateRoute 会直接跳转到 login 页面。
Danswerme
2019-12-28 10:15:26 +08:00
@simonv3ex 呃,你指的什么卡?
miniwade514
2019-12-28 10:39:16 +08:00
没记错的话,AjaxProvider 里的 useEffect 是在 Homepage 的 useEffect 之后执行的,所以你第一次发请求的时候,拦截器还没注册上
Danswerme
2019-12-28 10:52:36 +08:00
@miniwade514 谢谢指点!是这里的问题了,我研究研究应该将这个验证逻辑放到哪里去

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/633019

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX