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
相关产品推荐
相关产品推荐

