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

Redux Thunk结合Fetch API的错误处理标准实现方案

关于Redux Toolkit中createAsyncThunk结合Fetch API的标准错误处理方式

我找不到Redux Thunk结合Fetch API做错误处理的基础可用示例,参考教程实现后,请求返回404时无法触发rejected分支。修改Fetch逻辑后虽能触发分支,但错误信息的获取方式不符合预期,想了解标准实现方式。


状态定义

interface AppUserState {
  userId: string | undefined;
  user: User;
  status: 'idle' | 'pending' | 'succeeded' | 'failed';
  error: Error | null;
}

初始Thunk函数

export const fetchUser = createAsyncThunk(
  'app-user/fetch-user',
  async (id: string) => {
    const response = await fetch(`/api/v1/user/id/${id}`);
    return await response.json();
  }
);

初始Slice定义

const usersSlice = createSlice({
  name: 'app-user',
  initialState,
  reducers: {
    setUserId(state, action: PayloadAction<string | undefined>) {
      state.userId = action.payload;
    }
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchUser.pending.type, (state) => {
        state.status = 'pending';
      })
      .addCase(fetchUser.fulfilled.type, (state, action: PayloadAction<any>) => {
        if (state.status === 'pending') {
          state.status = 'succeeded';
          state.user = {
            id: action.payload.id,
            name: action.payload.name,
            type: action.payload.Type
          };
        }
      })
      .addCase(fetchUser.rejected.type, (state, action: PayloadAction<any>) => {
        if (state.status === 'pending') {
          state.status = 'failed';
          state.error = action.payload;
        }
      })
  }
});

核心问题

请求返回404时rejected分支未触发——因为Fetch API仅在网络故障时才会抛出Promise拒绝,HTTP错误状态码(如404、500)不会自动触发reject。


尝试修复后的代码

修改后的Thunk函数

export const fetchUser = createAsyncThunk(
  'app-user/fetch-user',
  async (id: string) => {
    const response = await fetch(`/api/v1/user/id/${id}`);
    if (!response.ok) {
      return Promise.reject(new Error(response.statusText));
    }
    return await response.json();
  }
);

修改后的rejected分支处理

.addCase(fetchUser.rejected.type, (state, action) => {
  if (state.status === 'pending') {
    state.status = 'failed';
    if ('error' in action) {
      state.error = action.error as Error;
    }
  }
})

但这种从action.error取错误的方式,感觉不是标准实现,想知道正确的处理姿势。


标准实现方式

1. Thunk函数规范抛出错误

使用Redux Toolkit提供的rejectWithValue方法传递错误信息,这是官方推荐的错误payload传递方式,能让错误信息规整地出现在action.payload中:

export const fetchUser = createAsyncThunk(
  'app-user/fetch-user',
  async (id: string, { rejectWithValue }) => {
    try {
      const response = await fetch(`/api/v1/user/id/${id}`);
      if (!response.ok) {
        // 尝试解析服务器返回的结构化错误信息,解析失败则用状态文本兜底
        const errorData = await response.json().catch(() => ({ message: response.statusText }));
        // 传递包含状态码和错误信息的自定义payload
        return rejectWithValue({
          status: response.status,
          message: errorData.message || '请求失败'
        });
      }
      return await response.json();
    } catch (err) {
      // 捕获网络层面的错误(如断网)
      return rejectWithValue({
        status: 0,
        message: err instanceof Error ? err.message : '网络请求失败'
      });
    }
  }
);

2. Slice中规范处理rejected分支

先定义错误类型,再直接从action.payload获取错误信息,类型更安全:

// 定义错误payload的类型
interface FetchError {
  status: number;
  message: string;
}

// 修改Slice的extraReducers部分
const usersSlice = createSlice({
  // ...其他配置不变
  extraReducers: (builder) => {
    builder
      // 注意:不需要再加.type,直接用fetchUser.pending/fulfilled/rejected即可
      .addCase(fetchUser.pending, (state) => {
        state.status = 'pending';
      })
      .addCase(fetchUser.fulfilled, (state, action) => {
        if (state.status === 'pending') {
          state.status = 'succeeded';
          state.user = {
            id: action.payload.id,
            name: action.payload.name,
            type: action.payload.Type
          };
        }
      })
      .addCase(fetchUser.rejected, (state, action: PayloadAction<FetchError | undefined>) => {
        if (state.status === 'pending') {
          state.status = 'failed';
          state.error = action.payload 
            ? new Error(`${action.payload.status}: ${action.payload.message}`) 
            : new Error('未知错误');
        }
      });
  }
});

3. 关键说明

  • Fetch API的特性:必须手动检查response.ok(状态码200-299时为true),否则HTTP错误不会触发Promise拒绝。
  • rejectWithValue是官方推荐的错误传递方式,相比直接Promise.reject,能让错误信息更规范地挂载到action.payload,而非仅依赖action.error。
  • 可以根据业务需求,在错误payload中携带更多服务器返回的详情,方便组件展示更精准的错误提示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 11:12:02