You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RTK Query遇401等4xx状态码时丢失响应体的解决问询

如何用RTK Query的fetchBaseQuery获取4xx状态码的响应体

问题背景

从RTK+axios迁移到RTK Query时,遇到接口返回401等4xx状态码时,fetchBaseQuery无法获取响应体,而axios可以正常拿到。接口返回的响应体格式如下:

{
  "timestamp": 123,
  "status": 401,
  "message": "Some useful message to the UI",
  "path": "/my-path-2"
}

原RTK Query代码使用默认fetchBaseQuery时,在onQueryStarted的catch块中只能拿到解析错误,无法获取响应体:

export const userApi = createApi({
  reducerPath: 'userApi',
  baseQuery: fetchBaseQuery({
    baseUrl: `api/`,
  }),
  endpoints: (builder) => ({
    loginUser: builder.mutation({
      query(data) {
        return {
          url: 'login',
          method: 'POST',
          body: data,
        };
      },
      async onQueryStarted(args, { dispatch, queryFulfilled }) {
        try {
          const res = await queryFulfilled;
          // 后续逻辑
        } catch (error) {
          console.error('error', JSON.stringify(error, null, 2));
          // 输出:{"data": undefined, "error": "TypeError: Cannot read property 'length' of undefined", "originalStatus": 401, "status": "PARSING_ERROR"}
        }
      },
    }),
});

目前已通过自定义axiosBaseQuery解决,但希望用原生fetchBaseQuery实现。

解决方案

要让fetchBaseQuery获取4xx的响应体,有两种直接的实现方式:

方法1:自定义validateStatus,将4xx标记为正常响应

默认情况下,fetchBaseQuery会把status >= 400的响应视为错误,跳过正常解析。我们可以修改validateStatus,仅将5xx及以上状态码标记为错误,之后在逻辑中自行判断响应状态:

export const userApi = createApi({
  reducerPath: 'userApi',
  baseQuery: fetchBaseQuery({
    baseUrl: `api/`,
    // 自定义状态校验规则:200-499都视为正常响应
    validateStatus: (response) => {
      return response.status >= 200 && response.status < 500;
    },
  }),
  endpoints: (builder) => ({
    loginUser: builder.mutation({
      query(data) {
        return {
          url: 'login',
          method: 'POST',
          body: data,
        };
      },
      async onQueryStarted(args, { dispatch, queryFulfilled }) {
        try {
          const res = await queryFulfilled;
          // 这里可以直接拿到4xx的响应体
          if (res.data.status >= 400) {
            console.error('错误提示:', res.data.message);
            // 处理4xx错误逻辑,比如弹窗提示、跳转登录页等
          } else {
            // 正常成功逻辑
          }
        } catch (error) {
          // 仅处理5xx或网络错误
        }
      },
    }),
});

方法2:扩展fetchBaseQuery,手动解析错误响应体

如果希望保留默认的错误捕获逻辑(4xx进入catch块),可以扩展fetchBaseQuery,在错误发生时手动解析响应对象:

const customFetchBaseQuery = async (args, api, extraOptions) => {
  const result = await fetchBaseQuery({
    baseUrl: 'api/',
  })(args, api, extraOptions);

  // 针对4xx错误,手动解析响应体
  if (result.error && result.error.originalStatus && result.error.originalStatus >= 400 && result.error.originalStatus < 500) {
    const rawResponse = result.error.data as Response;
    if (rawResponse instanceof Response) {
      try {
        const parsedError = await rawResponse.json();
        result.error.data = parsedError;
      } catch (e) {
        // 解析失败时保留原错误信息
      }
    }
  }

  return result;
};

export const userApi = createApi({
  reducerPath: 'userApi',
  baseQuery: customFetchBaseQuery,
  endpoints: (builder) => ({
    loginUser: builder.mutation({
      query(data) {
        return {
          url: 'login',
          method: 'POST',
          body: data,
        };
      },
      async onQueryStarted(args, { dispatch, queryFulfilled }) {
        try {
          const res = await queryFulfilled;
          // 正常逻辑
        } catch (error) {
          // 现在可以直接拿到error.data中的响应体内容
          console.error('错误提示:', error.data.message);
        }
      },
    }),
});

关键说明

  • 默认fetchBaseQuery遇到4xx错误时,会将原始的Response对象存放在error.data中,而非解析后的JSON,所以需要手动调用response.json()完成解析。
  • 方法1逻辑更简洁,适合需要统一处理成功/非致命错误的场景;方法2保留了默认的错误捕获流程,适合不想改动原有代码结构的场景。

内容的提问来源于stack exchange,提问作者Mateusgf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 12:54:53