req.files = 未定义(Multer、Express、Typescript)

问题描述 投票:0回答:1

我正在尝试将 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沟通。但我看不到任何接近的结果。

reactjs typescript express undefined multer
1个回答
0
投票

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中间件只查找该标头。

© www.soinside.com 2019 - 2024. All rights reserved.