我正在尝试将 imageUploads 保存到文件夹“/images”。我的问题是 req.files 由于某种原因似乎未定义。我会尝试发送我认为相关的代码。如有任何问题,请随时提出,我们将不胜感激! :)
//检查 if/else 块 输出:“没有文件”
后端代码:
adminRouter.post(
'/products/create',
upload.array('images', 5),
asyncHandler(async (req: Request, res: Response) => {
if (!req.body) {
res.status(400).json({ message: 'Product data not found' })
return
}
const {
name,
rating,
numReviews,
reviews,
slug,
price,
brand,
category,
countInStock,
description,
} = req.body
const images = (req.files as Express.Multer.File[]).map(
(file: Express.Multer.File) => file.path
)
if (req.files) {
console.log('Files:', req.files)
} else {
console.log('No files')
}
const product = new ProductModel({
name,
slug,
price,
brand,
category,
countInStock,
description,
images,
rating,
numReviews,
reviews,
})
try {
const createdProduct = await product.save()
res.status(201).json(createdProduct)
} catch (error) {
console.error('Error creating product:', error)
res.status(500).json({ message: 'Failed to create product' })
}
})
)
前端挂钩:
export const useCreateProductMutation = () => {
return useMutation({
mutationFn: async (product: {
name: string
slug: string
price: number
description: string
images: string[]
brand: string
category: string
rating: number
countInStock: number
numReviews: number
reviews: Review[]
}) => {
try {
const response = await apiClient.post<{ message: string }>(
`api/admin/products/create`,
product
)
return response.data
} catch (error) {
throw new Error('Failed to create product')
}
},
})
}
前端表单
export default function AdminCreateProductPage() {
const [formData, setFormData] = useState({
name: '',
price: 0,
images: [] as string[],
brand: '',
category: '',
countInStock: 0,
description: '',
slug: '',
rating: 0,
numReviews: 0,
reviews: [],
})
const { mutateAsync: createProduct } = useCreateProductMutation()
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files) {
const newImages = Array.from(e.target.files).map((file) =>
URL.createObjectURL(file)
)
setFormData({ ...formData, images: [...formData.images, ...newImages] })
}
}
const submitHandler = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
createProduct(formData)
}
return (
<div>
<h1>Edit Product</h1>
...
...
<Form onSubmit={submitHandler} encType="multipart/form-data">
<Row className="w-100">
<Col md={8}>
<Form.Group controlId="images">
<Form.Label>Images</Form.Label>
<Form.Control
type="file"
name="images"
multiple
onChange={handleImageChange}
/>
</Form.Group>
...
...
我尝试在网上寻找答案,并与chatGPT沟通。但我看不到任何接近的结果。
Multer 只处理
multipart/form-data
并且会忽略 application/json
您可能只是使用 json 对象作为正文而不是 FormData 来发表文章
而不是
const response = await apiClient.post<{ message: string }>(
`api/admin/products/create`,
product
)
你可能需要做类似的事情
const formData = new FormData();
product.images.forEach(imgBlob => {
// NOTE: you have to append the actual Blob/File and not an url created from URL.createObjectURL
formData.append('images', imgBlob);
});
formData.append('name', product.name);
... and all other fields
const response = await apiClient.post<{ message: string }>(
`api/admin/products/create`,
product
);
请参阅 https://developer.mozilla.org/en-US/docs/Web/API/FormData 了解更多信息
Content-type
是一个标头,有助于识别请求正文的格式。
大多数情况下,当您提供对象作为请求正文时,您使用的客户端会在发送到服务器的请求中自动用 Content-type
填充 application/json
基于此标头,服务器的中间件将解析正文。
对于文件上传,经常使用
multipart/form-data
,multer中间件只查找该标头。