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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 00:08:12