代码在这里 https://codesandbox.io/s/vigilant-napier-wzd4e
为什么拦截器里未能正常捕获 HomePage 组件里的 401 错误呢?将函数放入 setTimeout 里执行时又可以捕获到错误,麻烦大家帮我看看问题出在哪里。
1
manami 2019-12-28 09:07:17 +08:00
手机刷不出来代码。会不会是 axios 是异步请求导致的。“将函数放入 setTimeout 里执行时又可以捕获到错误”,setTimeout 严格意义上不是异步。
|
2
Danswerme OP 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} />; } |
3
Danswerme OP 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> ); } |
4
Danswerme OP 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); |
5
Danswerme OP @manami 代码我贴在楼上啦,你看看。 如果用按钮点击执行这个 ajax 函数时,axios 拦截器可以正常捕获到错误,而在组件刚挂载完时执行这个 ajax 函数就无法捕获到,不知道是哪里的问题。
|
8
Danswerme OP @manami 我也是菜鸟,以前都是直接将 axios 封装成一个 http 模块,然后在用到的地方引入。这次在 react-china http://react-china.org/t/topic/32941 看到了将 axios 直接放在 context 里的方法,特地用的试了下,结果就卡在这里了
|
9
miniwade514 2019-12-28 09:58:32 +08:00 via iPhone
在手机上艰难地看了很久,越看越懵逼。发请求这种事情为什么也要用 hooks,跟 react 组件的生命周期挂上钩,排查问题都不方便啊。
你说的能捕获,是指执行了 console.log("捕获到了") 那一行? |
10
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); }); |
11
Danswerme OP @miniwade514 是的,我指的捕获就是那一行。我是将用户 token 保存在 localStorage 里,用户信息、是否登录等状态放在 redux 里,每次第一次打开页面时会发请求去验证 token 是否合法,如果合法就将服务器返回的用户信息放进 redux 里,并将是否登录设置为 true。
不合法时服务器返回 401 就发起一个 dispatch,将是否登录设置为 false,下面的 PrivateRoute 会直接跳转到 login 页面。 |
13
miniwade514 2019-12-28 10:39:16 +08:00 via iPhone
没记错的话,AjaxProvider 里的 useEffect 是在 Homepage 的 useEffect 之后执行的,所以你第一次发请求的时候,拦截器还没注册上
|
14
Danswerme OP @miniwade514 谢谢指点!是这里的问题了,我研究研究应该将这个验证逻辑放到哪里去
|