redux 根据来自RTK查询API的403响应代码,响应本地访问令牌到期/更新

2fjabf4q  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(142)

我正在React Native + Redux Toolkit + Expo应用程序中调用使用RTK查询定义的API。这通过适当的身份验证/授权系统进行保护,即访问令牌(短期有效期)和刷新令牌(长期有效期)。
我希望避免检查任何访问令牌过期声明(我看到有人建议使用Redux中间件)。相反,如果可能的话,我希望在被请求的API返回403响应代码时触发访问令牌更新,即当访问令牌过期时。
下面是调用API的代码:

const SearchResults = () => {

  // get the SearchForm fields and pass them as the request body
  const { fields, updateField } = useUpdateFields();

  // query the RTKQ service
  const { data, isLoading, isSuccess, isError, error } =
    useGetDataQuery(fields);

  return ( ... )

RTK查询API定义如下:

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import * as SecureStore from "expo-secure-store";
import { baseUrl } from "~/env";

export const api = createApi({
  reducerPath: "api",
  baseQuery: fetchBaseQuery({
    baseUrl: baseUrl,
    prepareHeaders: async (headers, { getState }) => {
      // retrieve the access_token from the Expo SecureStore
      const access_token = await SecureStore.getItemAsync("access_token");
      if (access_token) {
        headers.set("Authorization", `Bearer ${access_token}`);
        headers.set("Content-Type", "application/json");
      }
      return headers;
    },
  }),
  endpoints: (builder) => ({
    getData: builder.query({
      // body holds the fields passed during the call
      query: (body) => {
        return {
          url: "/data",
          method: "POST",
          body: body,
        };
      },
    }),
  }),
});

export const { useGetDataQuery } = api;

我知道当API返回isError = trueerror = something 403时,我需要在Expo SecureStore中更新访问令牌(并且已经有一个功能用于此操作)。但是,当RTKQ API返回403响应代码时,我不知道如何再次快速查询RTKQ API,而用户几乎没有注意到。
谁能给我指个方向?

1zmg4dgp

1zmg4dgp1#

我已经掌握了窍门,非常感谢@phry!我不知道我怎么会错过RTKQ文档中的这个例子,但我毕竟是一个n 00 b。
话虽如此,这里介绍了如何重构RTKQapi来动态更新访问令牌,以防其他一些react原生初学者遇到这个问题。

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import * as SecureStore from "expo-secure-store";
import { baseUrl } from "~/env";
import { renewAccessToken } from "~/utils/auth";

// fetchBaseQuery logic is unchanged, moved out of createApi for readability
const baseQuery = fetchBaseQuery({
  baseUrl: baseUrl,
  prepareHeaders: async (headers, { getState }) => {
    // retrieve the access_token from the Expo SecureStore
    const access_token = await SecureStore.getItemAsync("access_token");
    if (access_token) {
      headers.set("Authorization", `Bearer ${access_token}`);
      headers.set("Content-Type", "application/json");
    }
    return headers;
  },
});

const baseQueryWithReauth = async (args, api) => {
  let result = await baseQuery(args, api);
  if (result.error) {
    /* try to get a new token if the main query fails: renewAccessToken replaces
    the access token in the SecureStore and returns a response code */
    const refreshResult = await renewAccessToken();
    if (refreshResult === 200) {
      // then, retry the initial query on the fly
      result = await baseQuery(args, api);
    }
  }
  return result;
};

export const apiToQuery = createApi({
  reducerPath: "apiToQuery",
  baseQuery: baseQueryWithReauth,
  endpoints: (builder) => ({
    getData: builder.query({
      // body holds the fields passed during the call
      query: (body) => {
        return {
          url: "/data",
          method: "POST",
          body: body,
        };
      },
    }),
  }),
});

export const { useGetDataQuery } = apiToQuery;

相关问题