2017-10-15 46 views
0

我有一箇中間件,可以在下一個動作運行前轉到刷新令牌,然後在訪問令牌到期時運行其他動作。REDX刷新令牌中間件

但是,如果我一次發出多個請求並且訪問令牌結束,我正在嘗試獲取儘可能多的刷新令牌。我正在檢查狀態中的isLoading屬性以防止這種情況。但是在請求之後,reducer中的isLoading值是真的,它在中間件中似乎是錯誤的,所以它一次又一次地請求。

我在fetching_refresh_token動作中發送refreshTokenPromise,但我從來沒有得到state.refreshTokenPromise,它總是未定義的。

我絕對有問題的狀態。

所以,這裏是我的問題,我怎樣才能訪問中間件的變化狀態值?

刷新令牌中間件:(這個版本打端點多次)

import { AsyncStorage } from 'react-native'; 
import { MIN_TOKEN_LIFESPAN } from 'react-native-dotenv'; 
import moment from 'moment'; 
import Api from '../lib/api'; 
import { 
    FETCHING_REFRESH_TOKEN, 
    FETCHING_REFRESH_TOKEN_SUCCESS, 
    FETCHING_REFRESH_TOKEN_FAILURE } from '../actions/constants'; 

export default function tokenMiddleware({ dispatch, getState }) { 
    return next => async (action) => { 
    if (typeof action === 'function') { 
     const state = getState(); 
     if (state) { 
     const expiresIn = await AsyncStorage.getItem('EXPIRES_IN'); 
     if (expiresIn && isExpired(JSON.parse(expiresIn))) { 
      if (!state.refreshToken.isLoading) { 
      return refreshToken(dispatch).then(() => next(action)); 
      } 
      return state.refreshTokenPromise.then(() => next(action)); 
     } 
     } 
    } 
    return next(action); 
    }; 
} 

async function refreshToken(dispatch) { 
    const clientId = await AsyncStorage.getItem('CLIENT_ID'); 
    const clientSecret = await AsyncStorage.getItem('CLIENT_SECRET'); 
    const refreshToken1 = await AsyncStorage.getItem('REFRESH_TOKEN'); 

    const userObject = { 
    grant_type: 'refresh_token', 
    client_id: JSON.parse(clientId), 
    client_secret: JSON.parse(clientSecret), 
    refresh_token: refreshToken1, 
    }; 

    const userParams = Object.keys(userObject).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(userObject[key])).join('&'); 

    const refreshTokenPromise = Api.post('/token', userParams).then(async (res) => { 
    await AsyncStorage.setItem('ACCESS_TOKEN', res.access_token); 
    await AsyncStorage.setItem('REFRESH_TOKEN', res.refresh_token); 
    await AsyncStorage.setItem('EXPIRES_IN', JSON.stringify(res['.expires'])); 

    dispatch({ 
     type: FETCHING_REFRESH_TOKEN_SUCCESS, 
     data: res, 
    }); 

    return res ? Promise.resolve(res) : Promise.reject({ 
     message: 'could not refresh token', 
    }); 
    }).catch((err) => { 
    dispatch({ 
     type: FETCHING_REFRESH_TOKEN_FAILURE, 
    }); 

    throw err; 
    }); 

    dispatch({ 
    type: FETCHING_REFRESH_TOKEN, 
    refreshTokenPromise, 
    }); 

    return refreshTokenPromise; 
} 

function isExpired(expiresIn) { 
    return moment(expiresIn).diff(moment(), 'seconds') < MIN_TOKEN_LIFESPAN; 
} 

刷新令牌減速機:

import { 
    FETCHING_REFRESH_TOKEN, 
    FETCHING_REFRESH_TOKEN_SUCCESS, 
    FETCHING_REFRESH_TOKEN_FAILURE } from '../actions/constants'; 

const initialState = { 
    token: [], 
    isLoading: false, 
    error: false, 
}; 

export default function refreshTokenReducer(state = initialState, action) { 
    switch (action.type) { 
    case FETCHING_REFRESH_TOKEN: 
     return { 
     ...state, 
     token: [], 
     isLoading: true, 
     }; 
    case FETCHING_REFRESH_TOKEN_SUCCESS: 
     return { 
     ...state, 
     isLoading: false, 
     token: action.data, 
     }; 
    case FETCHING_REFRESH_TOKEN_FAILURE: 
     return { 
     ...state, 
     isLoading: false, 
     error: true, 
     }; 
    default: 
     return state; 
    } 
} 

在此期間,當我把它發送到的getState到refreshToken功能,我得到了refreshToken中改變的狀態值。但是在這個版本中,刷新標記不經刷新而轉到其他操作。

猴補丁版本:(該版本不僅使1個請求)

import { AsyncStorage } from 'react-native'; 
import { MIN_TOKEN_LIFESPAN } from 'react-native-dotenv'; 
import moment from 'moment'; 
import Api from '../lib/api'; 
import { 
    FETCHING_REFRESH_TOKEN, 
    FETCHING_REFRESH_TOKEN_SUCCESS, 
    FETCHING_REFRESH_TOKEN_FAILURE } from '../actions/constants'; 

export default function tokenMiddleware({ dispatch, getState }) { 
    return next => async (action) => { 
    if (typeof action === 'function') { 
     const state = getState(); 
     if (state) { 
     const expiresIn = await AsyncStorage.getItem('EXPIRES_IN'); 
     if (expiresIn && isExpired(JSON.parse(expiresIn))) { 
      if (!state.refreshTokenPromise) { 
      return refreshToken(dispatch, getState).then(() => next(action)); 
      } 
      return state.refreshTokenPromise.then(() => next(action)); 
     } 
     } 
    } 
    return next(action); 
    }; 
} 

async function refreshToken(dispatch, getState) { 
    const clientId = await AsyncStorage.getItem('CLIENT_ID'); 
    const clientSecret = await AsyncStorage.getItem('CLIENT_SECRET'); 
    const refreshToken1 = await AsyncStorage.getItem('REFRESH_TOKEN'); 

    const userObject = { 
    grant_type: 'refresh_token', 
    client_id: JSON.parse(clientId), 
    client_secret: JSON.parse(clientSecret), 
    refresh_token: refreshToken1, 
    }; 

    if (!getState().refreshToken.isLoading) { 
    const userParams = Object.keys(userObject).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(userObject[key])).join('&'); 

    const refreshTokenPromise = Api.post('/token', userParams).then(async (res) => { 
     await AsyncStorage.setItem('ACCESS_TOKEN', res.access_token); 
     await AsyncStorage.setItem('REFRESH_TOKEN', res.refresh_token); 
     await AsyncStorage.setItem('EXPIRES_IN', JSON.stringify(res['.expires'])); 

     dispatch({ 
     type: FETCHING_REFRESH_TOKEN_SUCCESS, 
     data: res, 
     }); 

     return res ? Promise.resolve(res) : Promise.reject({ 
     message: 'could not refresh token', 
     }); 
    }).catch((err) => { 
     dispatch({ 
     type: FETCHING_REFRESH_TOKEN_FAILURE, 
     }); 

     throw err; 
    }); 

    dispatch({ 
     type: FETCHING_REFRESH_TOKEN, 
     refreshTokenPromise, 
    }); 

    return refreshTokenPromise; 
    } 
} 

function isExpired(expiresIn) { 
    return moment(expiresIn).diff(moment(), 'seconds') < MIN_TOKEN_LIFESPAN; 
} 

謝謝。

+0

我沒有看到你在哪裏檢查isLoading價值在中間件.. – Freez

+0

我試過其他的東西,修復它,你會再看看? – ccoeder

+0

當然!我好奇 – Freez

回答

0

你可以從終極版,傳奇受益

https://github.com/redux-saga/redux-saga

終極版,傳奇只是背景亞軍,監視你的行動,並在一些特定的動作滿足可以做出反應。你可以聽所有的行動和反應,或者您可以在評論中提到

https://redux-saga.js.org/docs/api/#takelatestpattern-saga-args

,而終極版,thunk是隻是另一種方式來創建在旅途中的行動和等待一些我只最新反應/ O發生,然後在I/O完成時創建更多操作。它更像是同步代碼模式,而redux-sagas更像多線程。在主線程上,你有你的應用程序運行和後臺線程你有傳說監視器和反應