重新发送使用过期令牌发出的请求会导致开发人员工具处于待处理状态

Posted

技术标签:

【中文标题】重新发送使用过期令牌发出的请求会导致开发人员工具处于待处理状态【英文标题】:Resending a request that was made with an expired token is leading to status pending in developer tools 【发布时间】:2021-02-13 21:23:18 【问题描述】:

我有一个反应应用程序,我正在尝试实现 JWT。

我正在使用axios 拦截器,在该拦截器中捕获由于令牌过期而由服务器返回的状态 401,将刷新令牌发送到服务器,在客户端接收新的访问令牌,然后重新发送原始失败的请求。

我面临的问题是,当我重新发送原始失败的请求时,状态在开发人员工具的网络选项卡中显示为永远挂起。最初失败的请求是一个 POST 请求,当我检查数据库时它已更新。那么为什么它在开发者工具中显示待处理状态呢?

这是我的 axios 拦截器代码

import axios from 'axios'
// import refreshToken from '../src/Store/refreshToken'
import  store  from '../src/index'
import  removeAuth  from '../src/Store/actions/authAction'

const api = axios.create(
    baseURL: process.env.REACT_APP_SERVER
) 

function createAxiosResponseInterceptor(axiosInstance) 
    axiosInstance.interceptors.request.use(function (config) 
        const token = localStorage.getItem('token');
        if (token)
            config.headers.Authorization = token;
            
        return config
        
    )

    axiosInstance.interceptors.response.use(
        response => 
            return response;
        ,
        error => 
            var errorStatus = error.response.status;
           
            
            if (errorStatus === 401)                                   // status 401 is used when token is expired
                let cookies = document.cookie
                let refresh = cookies.split("refresh=")[1].split(';')[0]
                if(!sendRefreshToken(refresh, error)) 
                    store.dispatch(removeAuth(isLoggedIn: false));
                    localStorage.setItem('token', '');
                    document.cookie = "refresh=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
                
            
            return error
        
    );


function sendRefreshToken(refreshToken, error) 
    let result = api.post('/refresh', 
                        refreshToken: refreshToken
                    )
                    .then(response => 
                        if (response.data.success && response.data.message === "new access token set") 
                            localStorage.setItem('token', response.data.newToken)
                            api(                                               // Here I am resending the failed request.
                                method: error.response.config.method,
                                url: error.response.config.url,
                                data: JSON.parse(error.response.config.data)
                            ).then(response => 
                                console.log(response)
                                return true
                            )
                            .catch(error => 
                                console.log(error)
                                return false
                            )
                        
                    )
                    .catch(error => 
                        console.log(error)
                        return false
                    )
    return result




createAxiosResponseInterceptor(api);

export default api;  

如果您发现代码有任何问题,请告诉我。让我知道这是否是正确的方法。开放以提供更多赏金积分。

【问题讨论】:

【参考方案1】:

请考虑这篇文章以供参考。 https://medium.com/swlh/handling-access-and-refresh-tokens-using-axios-interceptors-3970b601a5da

import axios from 'axios'
// import refreshToken from '../src/Store/refreshToken'
import  store  from '../src/index'
import  removeAuth  from '../src/Store/actions/authAction'

const api = axios.create(
    baseURL: process.env.REACT_APP_SERVER
)

function createAxiosResponseInterceptor(axiosInstance) 
    axiosInstance.interceptors.request.use(function (config) 
        const token = localStorage.getItem('token');
        if (token)
            config.headers.Authorization = token;
            
        return config
        
    )

    axiosInstance.interceptors.response.use(
        response => 
            return response;
        ,
        error => 
            var errorStatus = error.response.status;

            const originalRequest = error.config;
          
            if (
              error.response.status === 401 &&
              !originalRequest._retry
            ) 

              originalRequest._retry = true;
              return api
              .post('/refresh', 
                refreshToken: getRefreshToken()
            )

                .then((jsonRefreshResponse) => 
                  if (jsonRefreshResponse.status === 200) 


                    // 1) put token to LocalStorage
                    saveRefreshToken(
                      jsonRefreshResponse.data.refreshToken
                    );
                    // 2) Change Authorization header

                    const newAccessToken = getJwtToken();
                  
                    setAuthHeader(newAccessToken);


                    // 3) return originalRequest object with Axios.
                 //   error.response.config.headers[
                 //     "Authorization"
                 //   ] = `Bearer $newAccessToken`;
                    setAuthHeader(newAccessToken)
                    return axios(error.response.config);
                  
                )
                .catch((err) => 
                  console.warn(err);
                )

              

              if (error.config) 
                console.log(error.config);
                return Promise.reject();
              
        
    );


export const setAuthHeader = (token) => 
  api.defaults.headers.common["Authorization"] = `Bearer $token`;
;



createAxiosResponseInterceptor(api);

export default api;

//These methods could be in separate service class
const getJwtToken=()=> 
  return localStorage.getItem("token");

const getRefreshToken=() =>
  return localStorage.getItem("refreshToken");

const saveJwtToken=(token)=> 
  localStorage.removeItem("token");
  localStorage.setItem("token", token);

const saveRefreshToken=(refreshToken)=> 
  localStorage.setItem("refreshToken", refreshToken);

【讨论】:

对您的回答进行一些修改后,GET 请求重新发送成功,但 POST 请求在开发者工具中显示为cancelled saveRefreshToken(jsonRefreshResponse.data.refreshToken);应该是 saveJwtToken 没有刷新,因为如果你不改变你发送相同的令牌对吗?

以上是关于重新发送使用过期令牌发出的请求会导致开发人员工具处于待处理状态的主要内容,如果未能解决你的问题,请参考以下文章

使用过期令牌发出同时 API 请求时如何避免多个令牌刷新请求

如何刷新 jwt 并重新发送失败的 http 请求?

当我发送超过过期日期的令牌时,为啥会收到 401 错误?

Rails:发出 POST 请求时无法验证 CSRF 令牌的真实性

如何处理 Cognito 上的令牌过期问题

获取向 Rails 服务器发出请求的 API