Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用redux和redux saga刷新React应用程序中的令牌功能_Javascript_Reactjs_Redux_Jwt_Redux Saga - Fatal编程技术网

Javascript 使用redux和redux saga刷新React应用程序中的令牌功能

Javascript 使用redux和redux saga刷新React应用程序中的令牌功能,javascript,reactjs,redux,jwt,redux-saga,Javascript,Reactjs,Redux,Jwt,Redux Saga,我在React应用程序中刷新令牌流时遇到一些问题。 我使用axios拦截器处理statusCode===401的响应,刷新令牌,然后重复所有请求 Axios拦截器 export const customAxios = axios.create({ headers: { 'Access-Control-Allow-Origin': '*', 'Accept': 'application/json', "Content-Type": "application/json",

我在React应用程序中刷新令牌流时遇到一些问题。 我使用axios拦截器处理statusCode===401的响应,刷新令牌,然后重复所有请求

Axios拦截器

export const customAxios = axios.create({
  headers: {
    'Access-Control-Allow-Origin': '*',
    'Accept': 'application/json',
    "Content-Type": "application/json",
  }
});

customAxios.interceptors.response.use(
  function(response) {
    return response
  },
  function(error) {
    const errorResponse = error.response;
    if (isTokenExpiredError(errorResponse)) {
      return resetTokenAndReattemptRequest(error);
    }
    return Promise.reject(error);
  }
)
function isTokenExpiredError(errorResponse) {
  if (errorResponse.status === 401) {
    return true
  }
}

let isAlreadyFetchingAccessToken = false;
let subscribers = [];

async function resetTokenAndReattemptRequest(error) {
  const {dispatch, getState} = store;

  try {
    const { response: errorResponse } = error;
    const resetToken = getState().login.refreshToken;
    if (!resetToken) {
      return Promise.reject(error);
    }
    const retryOriginalRequest = new Promise(resolve => {
      addSubscriber(tokens => {
        errorResponse.config.headers.Authorization = 'Bearer ' + tokens.accessToken;
        resolve(axios(errorResponse.config));
      });
    });
    if (!isAlreadyFetchingAccessToken) {
      isAlreadyFetchingAccessToken = true;
      const response = await axios.get(`${API}/auth/refreshtoken`, configHeaders(resetToken))
      if (!response.data) {
        return Promise.reject(error);
      }
      const newTokens = response.data;
      dispatch(refreshTokenSuccess(newTokens))
      isAlreadyFetchingAccessToken = false;
      onAccessTokenFetched(newTokens);
    }
    return retryOriginalRequest;
  } catch (err) {
    return Promise.reject(err);
  }
}

function onAccessTokenFetched(tokens) {
  subscribers.forEach(callback => callback(tokens));
  subscribers = [];
}

function addSubscriber(callback) {
  subscribers.push(callback);
}
async function getAllVehicles (token, id, searchBy) {
  try {
    const res = await customAxios.post(`${API}/vehicle/getsorted?take=${15}`, 
      JSON.stringify({...searchBy, id }), configHeaders(token));
    return res.data;
  } catch (error) {
    throw error;
  }
}
而且效果很好!但是,当用户打开新的浏览器选项卡时,我遇到了刷新功能的问题。 在我的应用程序中,我有“在线”数据表,其中有一些
延迟
,用于重复请求

重播Saga actionChannel,用于延迟请求

export function * vehiclesWatcher () {
  let getVehiclesTask;
  const requestChan = yield actionChannel(GET_VEHICLES_REQUEST);
  while (true) {
    yield take(requestChan);
    getVehiclesTask = yield fork(vehiclesFlow);
    yield take([CLEAR_VEHICLES_REQUEST]);
    yield cancel(getVehiclesTask);
  }
}
车流

function * vehiclesFlow () {
  try {
    while (true) {
      const accessToken = yield select(getToken);
      const searchBy = yield select(result);
      const id = yield select(getId);
      const vehicles = yield call(getAllVehicles, accessToken, id, searchBy);
      yield put ({type: GET_VEHICLES_SUCCESS, payload: vehicles});
      yield delay(5000);
    }
  } catch (error) {

  } finally {
    if (yield cancelled()) {
      yield put({type: CLEAR_VEHICLES_SUCCESS});
    }
  }
}
获取所有车辆

export const customAxios = axios.create({
  headers: {
    'Access-Control-Allow-Origin': '*',
    'Accept': 'application/json',
    "Content-Type": "application/json",
  }
});

customAxios.interceptors.response.use(
  function(response) {
    return response
  },
  function(error) {
    const errorResponse = error.response;
    if (isTokenExpiredError(errorResponse)) {
      return resetTokenAndReattemptRequest(error);
    }
    return Promise.reject(error);
  }
)
function isTokenExpiredError(errorResponse) {
  if (errorResponse.status === 401) {
    return true
  }
}

let isAlreadyFetchingAccessToken = false;
let subscribers = [];

async function resetTokenAndReattemptRequest(error) {
  const {dispatch, getState} = store;

  try {
    const { response: errorResponse } = error;
    const resetToken = getState().login.refreshToken;
    if (!resetToken) {
      return Promise.reject(error);
    }
    const retryOriginalRequest = new Promise(resolve => {
      addSubscriber(tokens => {
        errorResponse.config.headers.Authorization = 'Bearer ' + tokens.accessToken;
        resolve(axios(errorResponse.config));
      });
    });
    if (!isAlreadyFetchingAccessToken) {
      isAlreadyFetchingAccessToken = true;
      const response = await axios.get(`${API}/auth/refreshtoken`, configHeaders(resetToken))
      if (!response.data) {
        return Promise.reject(error);
      }
      const newTokens = response.data;
      dispatch(refreshTokenSuccess(newTokens))
      isAlreadyFetchingAccessToken = false;
      onAccessTokenFetched(newTokens);
    }
    return retryOriginalRequest;
  } catch (err) {
    return Promise.reject(err);
  }
}

function onAccessTokenFetched(tokens) {
  subscribers.forEach(callback => callback(tokens));
  subscribers = [];
}

function addSubscriber(callback) {
  subscribers.push(callback);
}
async function getAllVehicles (token, id, searchBy) {
  try {
    const res = await customAxios.post(`${API}/vehicle/getsorted?take=${15}`, 
      JSON.stringify({...searchBy, id }), configHeaders(token));
    return res.data;
  } catch (error) {
    throw error;
  }
}
如果用户单击表中的一行,将在新选项卡中打开一个新组件,并发出一个新的服务器请求

在“新浏览器”选项卡中为“提出一个请求”重播Saga动作频道

export function * vehicleWatcher () {
  const requestChan = yield actionChannel(GET_VEHICLE_REQUEST);
  while (true) {
    const { id } = yield take(requestChan);
    yield fork(vehicleFlow, id);
  }
}
这是我的父窗口

如果我在服务器响应为401的同时单击表行,我将在新选项卡中获得响应401,我的刷新令牌请求将失败

你知道怎么解决这个问题吗?
当刷新令牌请求/刷新令牌成功操作正在进行时,如何暂停所有SAGA?

与其等待令牌过期,然后重试请求,不如在令牌过期之前刷新令牌?代币将包括其到期时间。更简单的方法是如Daniel所说提前刷新代币。另一个选择是,您可以尝试我决定只使用axios拦截器来刷新令牌逻辑中的方法