Redux-Toolkit 查询拦截器

Posted

技术标签:

【中文标题】Redux-Toolkit 查询拦截器【英文标题】:Redux-Toolkit query interceptor 【发布时间】:2021-10-05 10:05:39 【问题描述】:

我正在尝试构建一个拦截器,以应对访问令牌因 RTK 查询而变得无效的情况。 我已经通过文档中的示例构建了它,如下所示:

const baseQuery = fetchBaseQuery(
    baseUrl: BASE_URL,
    prepareHeaders: (headers,  getState ) => 
        const 
            auth: 
                user:  accessToken ,
            ,
         = getState() as RootState;
        if (accessToken) 
            headers.set('authorization', `Bearer $accessToken`);
        
        return headers;
    ,
);

const baseQueryWithReauth: BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError> = async (
    args,
    api,
    extraOptions
) => 
    let result = await baseQuery(args, api, extraOptions);

    if (result.error && result.error.status === 401) 
        const refreshResult = await baseQuery('token/refresh/', api, extraOptions);

        if (refreshResult.data) 
            api.dispatch(tokenUpdated( accessToken: refreshResult.data as string ));

            // retry the initial query
            result = await baseQuery(args, api, extraOptions);
         else 
            api.dispatch(logout());
        
    
    return result;
;

export const baseApi = createApi(
    reducerPath: 'baseApi',
    baseQuery: baseQueryWithReauth,
    endpoints: () => (),
);

问题是token/refresh/ 需要一个带有刷新令牌的POST 请求,我无法弄清楚如何重建这条const refreshResult = await baseQuery('token/refresh/', api, extraOptions); 行,以便它接受参数并发出POST 请求。

【问题讨论】:

知道如何区分对私有和公共端点的请求也很好 我很想知道你是如何让所有其他 api 切片从这个 baseQueryWithReauth 扩展而来的 @Jose Bernhardt 就这样export const yourApiName = baseApi.injectEndpoints( endpoints: (builder) =&gt; (), ); 谢谢,你知道是否有办法覆盖更多值吗? (我似乎无法在他们的文档中找到它)就像“注入”fetchBaseQuery 一样?如果您想用不同的baseUrl 注入端点,这样做会非常方便。 @JoseBernhardt 我不确定我理解你的意思。但我认为,如果您有 2 个单独的基本 URL,则将其端点放在单独的文件中是有意义的。类似someApi = baseApiMain.injectEndpointssomeOtherApi = baseApiSecondary.injectEndpoints 【参考方案1】:

你也可以用baseQuery('token/refresh/', api, extraOptions);代替

baseQuery(
  url: 'token/refresh/',
  method: 'POST'
, api, extraOptions);

fetchBaseQuery 的第一个参数正是您将从端点定义中的 query 函数返回的值。

至于您的另一个问题,我不知道您所说的“公共”和“私有”端点到底是什么意思。调用这些查询的是您的代码,所以您应该知道何时调用哪些查询?

【讨论】:

感谢您的回复。我在另一个问题中的意思是如何手动控制是否附加身份验证令牌?假设我有一些端点需要在通过身份验证时调用,但端点本身是公共的(不需要身份验证令牌)。据我了解,如果 prepareHeaders 方法在商店中找到它,则令牌将附加到每个请求 我认为在这些情况下发送令牌并没有什么坏处。如果这是一个具有完全不相关数据的外部服务(因此出于隐私原因您不想将令牌发送到那里),您还可以为此创建一个 seconds api。【参考方案2】:

我最近需要绕过将身份验证令牌添加到 refreshToken 请求。我通过创建一个使用 queryFn 而不是查询的端点来做到这一点:

tokenRefresh: builder.query<TokenRefreshResponse, void>(
    queryFn: async (arg, queryApi, extraOptions, baseQuery) => 
        const response = await fetch(`/api/refresh`);
        return (response.ok) ? data: await response.json()
                             : error: await response.json();
    
),

【讨论】:

以上是关于Redux-Toolkit 查询拦截器的主要内容,如果未能解决你的问题,请参考以下文章

通过拦截器在查询参数之前添加值

mybatis 实现 SQL 查询拦截修改详解

如何使 WCF 数据服务查询拦截器以 JSON 格式返回结果?

myBatis学习笔记(10)——使用拦截器实现分页查询

在 Angular 错误拦截器中等待模态承诺

MyBatis之拦截器分页