Redux RTK发送POST请求时服务端req.body为空问题排查
问题:RTK POST请求后端req.body为空,Thunder Client正常
问题详情
用Redux RTK开发小型宝可梦应用,需求是通过POST请求把pokemonID发送到接口,将宝可梦添加到图鉴。RTK发起请求时,网络面板能看到正常的载荷,但服务端的req.body是空的;用Thunder Client执行完全相同的操作时,后端却能正常接收数据,搞不懂为啥RTK请求里的pokemonId会丢失。
载荷示例
{pokemonId: 2}
前端使用代码
const [addToPokedex, { isLoading }] = useAddToPokedexMutation(); function handleClick() { addToPokedex(pokemon.id); }
RTK API配置
export const pokedexApiSlice = createApi({ reducerPath: 'pokedex', baseQuery: fetchBaseQuery({ baseUrl: `${endpoint}`, prepareHeaders(headers) { headers.set("Access-Control-Allow-Origin", react_app_domain); headers.set("Authorization", cookies.get('Authorization')); return headers; } }), tagTypes: ['pokedex'], endpoints(builder) { return { fetchPokedex: builder.query<PokemonApiResponse, void>({ query() { return '/list' }, providesTags: ["pokedex"] }), addToPokedex: builder.mutation<PokemonApiResponse, number>({ query: pokemonId => ({ url: '/catch', method: 'POST', body: JSON.stringify({ pokemonId }) }), invalidatesTags: ["pokedex"] }), removeFromPokedex: builder.mutation<PokemonApiResponse, number>({ query: pokemonId => ({ url: `/release/${pokemonId}`, method: 'DELETE', }), invalidatesTags: ["pokedex"] }) } } }) export const { useFetchPokedexQuery, useAddToPokedexMutation, useRemoveFromPokedexMutation } = pokedexApiSlice;
后端控制器代码
export const addToPokedex = asyncHandler(async (req: Request, res: Response): Promise<PokedexResponse> => { const { pokemonId } = req.body; const { userId } = res.locals; console.log("CATCH!") console.log(req.body) try { const pokedex: Pokedex = await PokedexModel.findOneAndUpdate( { userId: userId }, { $push: { pokemons: pokemonId } }, { new: true, upsert: true } ); return res.status(200).send({ success: true, pokemons: pokedex.pokemons || [] }) } catch (err: any) { return res.status(500).send({ success: false, message: err.message, pokemons: [] }) } });
问题原因
RTK的fetchBaseQuery会自动处理请求体的序列化,并且自动设置Content-Type: application/json头。但你手动用JSON.stringify()把body转成了字符串,这会导致:
- 请求的
Content-Type可能没有被正确设置为application/json - 后端的解析中间件(比如Express的
express.json())无法正确解析手动序列化的字符串格式
另外,你手动设置的Access-Control-Allow-Origin是服务端返回的响应头,客户端请求时设置这个头完全没用,还可能干扰请求。
修复步骤
- 移除手动JSON序列化:修改RTK mutation的
body,直接传入JavaScript对象,让fetchBaseQuery自动处理序列化和请求头:
addToPokedex: builder.mutation<PokemonApiResponse, number>({ query: pokemonId => ({ url: '/catch', method: 'POST', // 去掉JSON.stringify,直接传对象 body: { pokemonId } }), invalidatesTags: ["pokedex"] }),
- 删除无效的请求头设置:在
prepareHeaders里删掉Access-Control-Allow-Origin的设置:
prepareHeaders(headers) { // 删掉这行无效设置 // headers.set("Access-Control-Allow-Origin", react_app_domain); headers.set("Authorization", cookies.get('Authorization')); return headers; }
验证
修改完后重新发起请求,后端应该能正常打印出req.body,并正确获取到pokemonId了。
内容的提问来源于stack exchange,提问作者Nex
相关产品推荐
相关产品推荐

