使用 FileInterceptor 将本机图像上传与 FormData 反应到 NestJS 服务器,但“文件”未定义

Dha*_*gur 5 file-upload form-data multer react-native nestjs

我的 React Native 应用程序使用该库接收选定的图像react-native-image-picker,我需要将该图像发送到运行 NestJS 服务器的后端。端点使用@UseInterceptorFileInterceptor从收到的 formData 的“文件”字段中提取图像。但是,当我向端点发出请求时,收到的文件未定义。

\n

这是我的 React Native 代码,发送请求并将 FormData 中的文件作为有效负载。

\n
const uploadNewProfileImage = async () => {\n    if (!newProfileImage?.assets) return;\n    const formData = new FormData();\n    const profileImage = newProfileImage.assets[0];\n    console.log(profileImage);\n    if (profileImage.uri && user) {\n      formData.append(\n        'file',\n        JSON.stringify({\n          uri:\n            Platform.OS === 'android'\n              ? profileImage.uri\n              : profileImage.uri.replace('file://', ''),\n          name: profileImage.fileName,\n          type: profileImage.type\n        })\n      );\n      client // client is an Axios instance that injects Bearer Token\n        .post(`/user/profile/${user.uid}/image`, formData)\n        .then(({ data }) => {\n          console.log(data);\n        })\n        .catch((err) => {\n          console.log(err.response);\n          setShowImageUploadError(true);\n        })\n        .finally(() => {\n          getUserProfile();\n        });\n    }\n  };\n
Run Code Online (Sandbox Code Playgroud)\n

这是我提取文件的后端 NestJS 代码。

\n
// User.controller.ts\n@UseGuards(UserGuard)\n@ApiBearerAuth()\n@ApiUnauthorizedResponse({ description: 'Unauthorized' })\n@UseInterceptors(FileInterceptor('file', { limits: { fileSize: 20000000 } }))\n@Post('/profile/:uid/image')\n@ApiOkResponse({ type: UploadProfileResponse })\n@ApiBadRequestResponse({ description: 'Image too large OR Invalid image type' })\nasync uploadProfilePicture(@UploadedFile() file: Express.Multer.File, @Request() req): Promise<UploadProfileResponse> {\n    const uid = req.user.uid;\n    const imageUrl = await this.userService.uploadProfilePicture(uid, file);\n    return imageUrl;\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我尝试在 axios 配置中设置 axios 请求标头,如下所示

\n
{\n  headers: {\n    'Content-Type': 'multipart/form-data; boundary=\xe2\x80\x94\xe2\x80\x94file'\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我尝试将后端端点更改为以下内容

\n
@UseGuards(UserGuard)\n@ApiBearerAuth()\n@ApiUnauthorizedResponse({ description: 'Unauthorized' })\n@UseInterceptors(FileFieldsInterceptor([{ name: 'file' }], { limits: { fileSize: 20000000 } }))\n@Post('/profile/:uid/image')\n@ApiOkResponse({ type: UploadProfileResponse })\n@ApiBadRequestResponse({ description: 'Image too large OR Invalid image type' })\nasync uploadProfilePicture(@UploadedFiles() file: Array<Express.Multer.File>, @Request() req): Promise<UploadProfileResponse> {\n  const uid = req.user.uid;\n  console.log("File", file);\n  const imageUrl = await this.userService.uploadProfilePicture(uid, file[0]);\n  return imageUrl;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

似乎没有任何作用,从后端提取的文件仍然未定义。

\n

任何帮助将不胜感激。

\n

小智 0

我遇到了和你一样的问题,我花了几天时间才解决它。事实证明,当您使用 读取图像时react-native-image-picker,该fileName字段是null.

The image is:  {"assetId": null, "base64": null, "duration": null, "exif": null, 
"fileName": null, "fileSize": 282352, "height": 1472, "type": "image", 
"uri": "file:///..../ImagePicker/73C6B334-2F8F-4588-92FA-C83E11B76B74.png", 
"width": 2456}
Run Code Online (Sandbox Code Playgroud)

所以你只需要为上传的图片修改一个名称:

  formData.append('file', {
    uri: profileImage.uri,
    type: profileImage.type,
    name: 'image.jpg',
  });
Run Code Online (Sandbox Code Playgroud)

并且您不需要在附加数据时也不需要stringify像这样转换 URL:

uri:
        Platform.OS === 'android'
          ? profileImage.uri
          : profileImage.uri.replace('file://', ''),
Run Code Online (Sandbox Code Playgroud)