簡體   English   中英

redux-saga:令牌刷新后重試捕獲的操作

[英]redux-saga: retry catched actions after token refresh

我在redux-saga頻道中分組了一組操作。 它們中的每個(或同時)可能由於令牌過期而失敗。 如何暫停以后的操作以防止下次失敗,在刷新令牌和取消暫停通道后重試已捕獲的操作。

function* watchRequests() {
    // a set of simultaneous actions which utilize access token from store
    const requestChannel = yield actionChannel('*_REQUEST')
    while (true) {
        try {
            const { payload } = yield take(requestChannel)

            yield fork(handleRequest, payload)
        } catch (error) {
            if (error === 'EXPIRED_ACCESS_TOKEN') {
                const newToken = yield call(refreshToken)
                yield call(setAccessToken, newToken)
            } else {
                throw error
            }
        } finally {
            // after success token refresh
            // 1. retry catched action
            // 2. unsuspend rest actions from channel
        }
    }
}

在這里處理相同的概念,但是使用不同的配方。

以下是代碼的關鍵部分,但請注意,它仍在進行中。

關鍵是派生了“ api.refreshSession”,並且在此任務仍在運行時,每個REFRESH_SESSION操作都將加入已在運行的任務,而不是啟動一個新任務。

function* refreshSessionListener() {
    let task;
    while (true) {
        const action = yield take(REFRESH_SESSION);
        if (task === undefined || !task.isRunning()) {
            task = yield fork(api.refreshSession);
        }
        // non-blocking join
        yield fork(joinRefreshSessionTask, task, action);
    }
}

function* joinRefreshSessionTask(task, action) {
    const response = yield join(task);
    if (response.status === 200) {
        yield fork(action.onSuccess);
    } else {
        yield fork(action.onError, response);
    }
}

export function* apiSaga(...args) {
    const [fn, { type, payload, meta = {} }] = args;
    try {
        const data = yield call(fn, payload);
        yield* okSaga(type, e);
    } catch (e) {
        if (e.tokenExpired) {
            yield put({
                type: REFRESH_SESSION,
                onSuccess: apiSaga.bind(null, ...args),
                onError: errorSaga.bind(null, type)
            });
            return;
        } else {
            yield* errorSaga(type, e);
        }
    }
}

runSaga(refreshSessionListener)

我在應用程序的其他部分使用上述內容:

import {apiSaga} from ...

function* listenToActions () {
    yield takeEvery(POST_SOMETHING, apiSaga.bind(null, api.postSomething));
    yield takeLatest(GET_SOMETHING, apiSaga.bind(null, api.getSomething));
}

runSaga(listenToActions);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM