RTK查询拦截多个请求

RTK query interceptor multiple requests

我的 RTK 查询拦截器有问题,我通过扩展每个 RTK query documentation 的 fetchBaseQuery 实现了自动重新授权,现在我有一个问题,如果多个请求被触发并且令牌无效所有这些都将得到 401 作为响应,并且所有这些都将尝试刷新令牌,这将导致第一个成功,其他将失败,然后其他将触发并且 return 用户登录屏幕.

有什么办法可以避免这种情况吗?

  let result = await baseQuery(args, api, extraOptions)
      if (result.error && result.error.status === 401) {
        // try to get a new token
        const refreshResult = await baseQuery(
          {
          url: `http://.../${refreshToken}`,
          method: 'POST'
          }, 
          api, 
          extraOptions
        );
        if (refreshResult.data) {
          // store the new token
          api.dispatch(tokenReceived(refreshResult.data))
          // retry the initial query
          result = await baseQuery(args, api, extraOptions)
        } else {
          api.dispatch(loggedOut())
        }
      }
      return result

一个可能的解决方案是使用互斥锁。我们在 this github discussion:

中讨论了可能的解决方案
import { Mutex } from 'async-mutex';

const mutex = new Mutex();

const baseQueryWithReauth = async (args, api, extraOptions) => {
  await mutex.waitForUnlock();
  let result = await baseQuery(args, api, extraOptions);

  if (result.error && result.error.status === 401) {
    if (!mutex.isLocked()) {
      const release = await mutex.acquire();

      try {
        const refreshResult = await baseQuery(
          {
            url: 'auth/refresh/',
            method: 'POST',
            body: { getToken(), getRefreshToken() },
          },
          api,
          extraOptions,
        );

        if (refreshResult.data) {
          api.dispatch(tokenUpdated(refreshResult.data));

          // retry the initial query
          result = await baseQuery(args, api, extraOptions);
        } else {
          api.dispatch(logout());
        }
      } finally {
        release();
      }
    } else {
      await mutex.waitForUnlock();
      result = await baseQuery(args, api, extraOptions);
    }
  }

  return result;
};

const baseApi = createApi({
  baseQuery: baseQueryWithReauth,
  endpoints: () => ({}),
});