如何在 axios 拦截器中编写重定向而不在 React JS 中重新加载

Posted

技术标签:

【中文标题】如何在 axios 拦截器中编写重定向而不在 React JS 中重新加载【英文标题】:How to write redirection inside the axios interceptors without reloading in React JS 【发布时间】:2019-11-19 00:21:22 【问题描述】:

我使用 axios 拦截器来维护内部服务器错误。如果响应有错误而不重新加载,我需要重定向到另一个 url。下面的代码我使用了 location.href。所以它正在重新加载。我需要一个解决方案来重定向而不刷新页面。

我在 react-router-dom 中尝试了“重定向”。但这对我不起作用。

export function getAxiosInstance() 
    const instance = axios.create();
    const token    = getJwtToken();

    // Set the request authentication header
    instance.defaults.headers.common['Authorization'] = `Bearer $token`;

    // Set intercepters for response
    instance.interceptors.response.use(
        (response) => response,
        (error) => 
            if (config.statusCode.errorCodes.includes(error.response.status)) 
                return window.location.href = '/internal-server-error';
            

            return window.location.href = '/login';
        
    );

    return instance;

谁能帮我解决这个问题?

【问题讨论】:

你在使用 Redux 吗? @MosèRaguzzini 是的,我是。 好的,您可以导入您的商店实例并调度在这种情况下将更改路线的操作。或者您可以在我的回答中采用以下解决方案。 @MosèRaguzzini 谢谢。我会试试你的解决方案。 【参考方案1】:

这将利用导入缓存

// history.js
import  createBrowserHistory  from 'history'

export default createBrowserHistory(
  /* pass a configuration object here if needed */
)


// index.js (example)
import  Router  from 'react-router-dom'
import history from './history'
import App from './App'

ReactDOM.render((
  <Router history=history>
    <App />
  </Router>
), holder)


// interceptor.js
import axios from 'axios';
import cookie from 'cookie-machine';
import history from '../history';

axios.interceptors.response.use(null, function(err) 
  if ( err.status === 401 ) 
    cookie.remove('my-token-key');
    history.push('/login');
  

  return Promise.reject(err);
);

【讨论】:

我使用了历史库。它对我不起作用。只更改了浏览器网址。不重定向。 你必须导出 browserHistory 的实例,而不是 browserHistory 本身 我在你的回答中做了同样的事情。我使用的是 react-router-dom 中的 'BrowserRouter' 而不是“Router”。 “导出 browserHistory 的实例,而不是 browserHistory 本身”是什么意思。 看一下我的history.js文件,如果它为app和axios抽象都是这样导出的,它们引用同一个历史对象 我在没有 redux 的时候使用这个方法,而使用 redux 我只是调度一个作用于同一个历史对象的动作【参考方案2】:

我通过将 useHistory()&lt;Router&gt; 内部传递给 axios 拦截器解决了这个问题。

App.js:

// app.js

function App() 
  return (
    <Router>
      <InjectAxiosInterceptors />

      <Route ... />
      <Route ... />
    </Router>
  )

InjectAxiosInterceptors.js:

import  useEffect  from "react"
import  useHistory  from "react-router-dom"
import  setupInterceptors  from "./plugins/http"

function InjectAxiosInterceptors () 
  const history = useHistory()

  useEffect(() => 
    console.log('this effect is called once')
    setupInterceptors(history)
  , [history])

  // not rendering anything
  return null

插件/http.js:

import axios from "axios";

const http = axios.create(
  baseURL: 'https://url'
)

/**
 * @param import('history').History history - from useHistory() hook
 */
export const setupInterceptors = history => 
  http.interceptors.response.use(res => 
    // success
    return res
  , err => 
    const  status  = err.response
  
    if (status === 401) 
      // here we have access of the useHistory() from current Router
      history.push('/login')
    
  
    return Promise.reject(err)
  )


export default http

【讨论】:

【参考方案3】:

您应该使用历史对象来推送新位置。检查这个问题How to push to History in React Router v4?。这应该会有所帮助。

【讨论】:

我使用了历史库。它对我不起作用。只更改了浏览器网址。不会发生重定向。

以上是关于如何在 axios 拦截器中编写重定向而不在 React JS 中重新加载的主要内容,如果未能解决你的问题,请参考以下文章

React 路由器 + Axios 拦截器。如何进行重定向?

如何使用 React Router V4 从 axios 拦截器重定向?

vue 和 react 的登录态拦截

防止 axios/fetch 重定向

Vue2学习小记-给Vue2路由导航钩子和axios拦截器做个封装

从 React Native 中的 api 拦截器(组件外部)重定向到屏幕