React上传图片至Strapi遇500错误,请求修复方案
修复Strapi表单提交图片时的500错误
问题根源
- Strapi的文件上传需单独调用
/upload接口,不能直接将文件数据和普通表单字段一起提交到实体接口(如/links),否则会触发500错误。 - 原代码中处理
file类型输入的逻辑错误,无法正确获取文件对象,导致上传数据格式不合法。 - 复选框的状态处理逻辑错误,无法正确获取选中状态。
修复方案
1. 修正输入处理逻辑
针对文件输入和复选框单独处理,确保能正确获取对应值:
const handleChange = (e) => { const name = e.target.name; let value = e.target.value; // 处理文件输入,获取真实文件对象 if (e.target.type === "file") { value = e.target.files[0]; } // 处理复选框,获取选中状态 if (e.target.type === "checkbox") { value = e.target.checked; } setInputs((values) => ({ ...values, [name]: value })); };
2. 调整提交流程:先传文件再创建实体
先通过/upload接口上传图片,拿到文件ID后,再将ID与其他表单数据一起提交到/links接口完成关联:
const handleSubmit = async (e) => { e.preventDefault(); let featuredImageId = null; // 上传图片(如果用户选择了图片) if (inputs.featuredimg) { const formData = new FormData(); formData.append("files", inputs.featuredimg); // 关联到Link模型的featuredimg字段(需和Strapi模型配置一致) formData.append("ref", "api::link.link"); formData.append("field", "featuredimg"); try { const uploadRes = await axios.post( `${backendUrl}/api/upload`, formData, { headers: { Authorization: `Bearer ${token}`, "Content-Type": "multipart/form-data" } } ); featuredImageId = uploadRes.data[0].id; } catch (uploadError) { console.error("图片上传失败:", uploadError); return; } } // 提交Link数据 try { const linkRes = await axios.post( `${backendUrl}/api/links`, { data: { userid: user.id, slug: inputs.name.replace(/\W+/g, "-") + "-" + randomNumberForSlug, url: inputs.url, name: inputs.name, body: inputs.body, type: inputs.type, nsfw: inputs.nsfw || false, public: inputs.public !== undefined ? inputs.public : true, featuredimg: featuredImageId, }, }, { headers: { Authorization: `Bearer ${token}` } } ); console.log("链接创建成功:", linkRes); } catch (linkError) { console.error("链接创建失败:", linkError); } };
3. 修正文件输入组件的属性
文件输入无法通过value绑定状态,直接移除该属性:
<Input type="file" name="featuredimg" placeholder="Featured Image" onChange={handleChange} />
完整修改后的代码
import React, { useState } from "react"; import { Button, FormControl, FormLabel, Input, Checkbox, VStack, Select, Heading, Textarea, } from "@chakra-ui/react"; import { useSelector } from "react-redux"; import axios from "axios"; const backendUrl = process.env.REACT_APP_API_URL; export default function AddLinkView() { const { user } = useSelector((state) => state.user); const token = localStorage.getItem("jwt"); const [inputs, setInputs] = useState({}); const handleChange = (e) => { const name = e.target.name; let value = e.target.value; if (e.target.type === "file") { value = e.target.files[0]; } if (e.target.type === "checkbox") { value = e.target.checked; } setInputs((values) => ({ ...values, [name]: value })); }; const randomNumberForSlug = Math.floor(Math.random() * 10000); const handleSubmit = async (e) => { e.preventDefault(); let featuredImageId = null; if (inputs.featuredimg) { const formData = new FormData(); formData.append("files", inputs.featuredimg); formData.append("ref", "api::link.link"); formData.append("field", "featuredimg"); try { const uploadRes = await axios.post( `${backendUrl}/api/upload`, formData, { headers: { Authorization: `Bearer ${token}`, "Content-Type": "multipart/form-data" } } ); featuredImageId = uploadRes.data[0].id; } catch (uploadError) { console.error("图片上传失败:", uploadError); return; } } try { const linkRes = await axios.post( `${backendUrl}/api/links`, { data: { userid: user.id, slug: inputs.name.replace(/\W+/g, "-") + "-" + randomNumberForSlug, url: inputs.url, name: inputs.name, body: inputs.body, type: inputs.type, nsfw: inputs.nsfw || false, public: inputs.public !== undefined ? inputs.public : true, featuredimg: featuredImageId, }, }, { headers: { Authorization: `Bearer ${token}` } } ); console.log("链接创建成功:", linkRes); } catch (linkError) { console.error("链接创建失败:", linkError); } }; return ( <> <form onSubmit={handleSubmit}> <FormControl bg="white" p={6} rounded="xl" > <Heading as="h1" size="xl" pb={6}> Ajouter un article </Heading> <VStack spacing={2} align="stretch" w="75%"> <FormLabel>URL</FormLabel> <Input bg="white" type="text" name="url" placeholder="Add your URL" value={inputs.url || ""} onChange={handleChange} /> <FormLabel>Titre</FormLabel> <Input bg="white" type="text" name="name" placeholder="Name" value={inputs.name || ""} onChange={handleChange} /> <FormLabel>Image</FormLabel> <Input type="file" name="featuredimg" placeholder="Featured Image" onChange={handleChange} /> <FormLabel>Description </FormLabel> <Textarea bg="white" name="body" placeholder="Add your description" value={inputs.body || ""} onChange={handleChange} /> <FormLabel>Type</FormLabel> <Select placeholder="Select option" name="type" value={inputs.type || ""} onChange={handleChange} > <option value="lien">lien</option> <option value="image">image</option> <option value="video">video</option> </Select> <FormLabel>Votre lien est pour un public adulte ?</FormLabel> <Checkbox colorScheme="red" bg="white" name="nsfw" isChecked={inputs.nsfw || false} onChange={handleChange} > Adult only </Checkbox> <FormLabel>Rendre ce lien privé</FormLabel> <Checkbox colorScheme="red" bg="white" name="public" isChecked={inputs.public !== undefined ? inputs.public : true} onChange={handleChange} > Private link </Checkbox> <Button colorScheme="green" type="submit" w={{ base: "100%", md: "max-content" }} > Submit </Button> </VStack> </FormControl> </form> </> ); }
额外注意事项
- 确保Strapi的
Link模型中已创建featuredimg字段,类型设置为Media(单文件)。 - 检查Strapi权限配置,确保
upload和links接口的创建权限对已认证用户开放。
内容的提问来源于stack exchange,提问作者frontcodelover
相关产品推荐
相关产品推荐

