描述的问题
我们正在使用auth0 API和React Native应用程序,并使用拦截器将auth令牌注入每个请求的头部。我们遇到的问题是,在Android(模拟器和设备上)上,拦截器似乎不会立即生效,因此我们发出的第一个请求没有被拦截。
我们可以使用一个肮脏的setTimeout
技巧来延迟渲染使API调用的组件几百毫秒,但这感觉像是一个脆弱的解决方法。
重现问题
重现这个问题确实需要一个异步API,如react-native-auth0
。因为这个API是基于钩子的,所以我们使用useEffect
与children
一起 Package 组件以安装和删除拦截器。在初始化过程中,我们设置另一个状态标志,表示不要在添加拦截器后立即渲染children
。然而,在安装拦截器后立即渲染才是痛苦的地方。
我们使用@tanstack/react-query
进行API调用,当我们的主页面渲染时,我们会发起一个获取数据的调用。这是第一个未被拦截的调用。在应用程序流程中的后续调用工作正常。如果API不可用并且我们让查询重试,那么随后的重试会被拦截。
所以我们的特殊组件用于安装拦截器:
function AuthGuard(props) {
const [init, setInit] = React.useState(false);
const auth0 = useAuth0();
React.useEffect(() => {
const requestInterceptor = axios.interceptors.request.use(
async (config) => {
// Do we have a token?
const hasCredentials = await auth0.hasValidCredentials();
if (hasCredentials) {
try {
// Get the access token from auth0
const credentials = await auth0.getCredentials();
// Add the access token to the request
if (credentials) {
config.headers.Authorization = `Bearer ${credentials.accessToken}`;
}
} catch (err) {
console.log(err);
}
}
return config;
},
(error) => Promise.reject(error)
);
// Without this timeout the first request made when rendering the children on Android will not be intercepted
setTimeout(() => {
setInit(true);
}, 100);
return () => {
setInit(false);
axios.interceptors.request.eject(requestInterceptor);
};
}, [auth0]);
return init ? props.children : null;
}
然后我们用这个组件包裹我们的应用程序,如下所示:
export default function App() {
return (
<Auth0Provider
domain="OUR_DOMAIN"
clientId="OUR_CLIENT_ID"
>
<QueryClientProvider client={queryClient}>
<AuthGuard>
<HomeScreen />
</AuthGuard>
</QueryClientProvider>
</Auth0Provider>
);
}
我们的HomeScreen
如下所示:
export function Home() {
const query = useQuery({
queryKey: ["our-query"],
queryFn: async () => {
const res = await axios.get("https://api.backend.dev/our-query");
return res.data;
},
});
return <Text>Hello, world!</Text>
}
代码片段
- 无响应*
预期行为
我们希望在用axios.interceptors.request.use
安装拦截器后,拦截器能够立即开始工作。理想情况下,我们可以等待拦截器安装完成,以避免使用一个讨厌的setTimeout
来延迟渲染子组件。
Axios版本
1.5.0
适配器版本
- 无响应*
浏览器
- 无响应*
浏览器版本
- 无响应*
Node.js版本
18.17.1
OS
Android 13
其他库版本
react-native@0.72.4
expo@49.0.10
其他上下文/截图
- 无响应*
5条答案
按热度按时间ecr0jaav1#
你好,@robcaldecott
你确定在第一次axios调用之前调用了'useEffect'吗?
似乎与#5843(评论)有关。
dzjeubhm2#
我认为你应该在auth0未准备好时跳过设置拦截器,通过检查
auth0.isLoading
。7uhlpewt3#
尝试这个
6xfqseft4#
你好,@robcaldecott 。你确定在第一次axios调用之前调用了'useEffect'吗?这似乎与#5843有关(评论)
我绝对肯定。这就是为什么我使用了那个
init
状态,它最初是false
。4zcjmb1e5#
我通过在模块级别安装拦截器来解决这个问题,基于对这个问题的回应:
https://community.auth0.com/t/how-to-get-token-from-outside-react-components/68756/3
这意味着
axios.interceptors.request.use
会在应用加载时立即被调用,这似乎足以解决Android问题。