RTK Query中PUT请求400错误求助:Strapi API更新失败
React + Strapi 更新数据400错误解决
问题描述
用React开发CRUD应用,基于Redux Toolkit和useContext管理状态,查询、新增、删除功能正常,但调用Strapi REST API执行数据更新时返回400 Bad Request,错误提示为Missing "data" payload in the request body,请求体处理存在适配问题。
Redux-Toolkit 切片文件 petApi.js
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const petApi = createApi({ reducerPath: 'petApi', baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:1337/api' }), tagTypes: ['Pet'], endpoints: (builder) => ({ getPets: builder.query({ query: () => '/pets', providesTags: ['Pet'], }), addNewPet: builder.mutation({ query: (payload) => ({ url: '/pets', method: 'POST', body: payload, headers: { 'Content-type': 'application/json; charset=UTF-8', }, }), invalidatesTags: ['Pet'], }), updatePet: builder.mutation({ query: ({id, ...rest}) => ({ url: `/pets/${id}`, method: 'PUT', body: rest, }), invalidatesTags: ['Pet'], }), deletePet: builder.mutation({ query: (id) => ({ url: `/pets/${id}`, method: 'DELETE', }), invalidatesTags: ['Pet'], }), }) }) export const { useGetPetsQuery, useGetPetQuery, useAddNewPetMutation, useUpdatePetMutation, useDeletePetMutation, } = petApi;
提交表单组件 editPetEntry.js
import React, { useState, useEffect } from 'react'; // mui components import { Typography, TextField, Box, Button, Paper } from '@mui/material'; // mui icons import { Edit } from '@mui/icons-material'; // custom components import BottomNav from './BottomNav'; import { useUpdatePetMutation } from '../services/petApi'; import Loader from './Loader'; import { useParams } from 'react-router-dom'; import { usePetContext } from '../petContext'; export default function EditPetEntry() { // input data const [name, setName] = useState(""); const [animal, setAnimal] = useState(""); const [breed, setBreed] = useState(""); const [age, setAge] = useState(""); const [location, setLocation] = useState(""); const [sex, setSex] = useState(""); // const {id} = useParams(); const { petId } = usePetContext(); // edit req const [updatePet, { isLoading }] = useUpdatePetMutation(); const data = JSON.stringify({ "data": { "name": name, "animal": animal, "breed": breed, "age": age, "location": location, "sex": sex } }); const handleEditPet = () => { updatePet({ id: petId, data }); }; console.log(data); console.log(petId); return ( <Box component="form" sx={{ '& .MuiTextField-root': { m: 1, width: '50ch' }, display: 'flex', flexDirection: 'column' }} noValidate autoComplete="off" > <div> <Typography variant="h3" gutterBottom component="div"> Edit Pet entry </Typography> <TextField required id="filled-name" label="Name" variant="outlined" onChange={(e) => setName(e.target.value)} /> <TextField required id="filled-animal" label="Animal" variant="outlined" helperText="Cat, Dog, Bird" onChange={(e) => setAnimal(e.target.value)} /> <TextField required id="filled-breed-input" label="Breed" variant="outlined" onChange={(e) => setBreed(e.target.value)} /> <TextField required id="filled-location-input" label="Location" variant="outlined" onChange={(e) => setLocation(e.target.value)} /> <TextField required id="filled-age" label="Age" type="number" variant="outlined" onChange={(e) => setAge(e.target.value)} /> <TextField required id="sex" label="Sex" helperText="Male, Female" variant="outlined" onChange={(e) => setSex(e.target.value)} /> </div> <div> <Button variant="outlined" onClick={handleEditPet} startIcon={<Edit />}> Edit Pet Entry </Button> {isLoading && <Loader />} </div> <Paper sx={{ position: 'fixed', bottom: 0, left: 0, right: 0 }} elevation={3}> <BottomNav /> </Paper> </Box> ); }
PUT请求响应
{"data":null,"error":{"status":400,"name":"ValidationError","message":"Missing \"data\" payload in the request body","details":{}}
请求负载
{ "data": "{\"data\":{\"name\":\"white\",\"animal\":\"cat\",\"breed\":\"jsdkhj\",\"age\":\"9\",\"location\":\"kjcjsk\",\"sex\":\"male\"}}" }
响应头
Request URL: http://localhost:1337/api/pets/13 Request Method: PUT Status Code: 400 Bad Request Remote Address: 127.0.0.1:1337 Referrer Policy: strict-origin-when-cross-origin Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: http://localhost:3000 Connection: keep-alive Content-Length: 131 Content-Security-Policy: connect-src 'self' https:;img-src 'self' data: blob: https://dl.airtable.com;media-src 'self' data: blob:;default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline' Content-Type: application/json; charset=utf-8 Date: Mon, 20 Mar 2023 13:53:23 GMT Expect-CT: max-age=0
问题原因
从请求负载能看出,data字段的值是字符串化后的JSON,而Strapi需要的是原生JSON对象。这是因为在editPetEntry.js中手动调用了JSON.stringify()处理请求数据,但Redux Toolkit的fetchBaseQuery会自动将请求体序列化为JSON,导致双重序列化,最终Strapi无法识别正确的data payload。
解决方案
修改editPetEntry.js中的数据处理逻辑,去掉JSON.stringify(),直接传递原生对象:
// 替换原来的data定义 const data = { "data": { "name": name, "animal": animal, "breed": breed, "age": age, "location": location, "sex": sex } }; // 调用updatePet时展开data对象 const handleEditPet = () => { updatePet({ id: petId, ...data }); };
或者也可以直接在调用时构造参数:
const handleEditPet = () => { updatePet({ id: petId, data: { name, animal, breed, age, location, sex } }); };
另外,addNewPet中的headers配置可以移除,因为fetchBaseQuery默认会设置Content-Type: application/json,无需手动添加。
内容的提问来源于stack exchange,提问作者keyzcharly
相关产品推荐
相关产品推荐

