无法发送带有图像(多部分/表单)React Native EXPO、Spring 作为后端的 POST 请求

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

无法发送带有图像的 POST 请求(多部分/表单)React Native EXPO,Spring 作为后端

handlePost

const handlePost = async () => {
    const formDataToSend = new FormData();

    const advertisementBlob = new Blob([JSON.stringify(formData)], {
      type: "application/json",
    });
    formDataToSend.append("advertisement", advertisementBlob);
    imageUris.forEach((img) => {
      const media = {
        uri: img,
        type: "image/jpeg",
        name: "profile.jpg",
      };
      // const file = new File([blob]);
      formDataToSend.append("files", media);
    });
    try {
      console.log(JSON.stringify(formDataToSend));
      const result = await postAdd(formDataToSend);
      console.log(result);
    } catch (error) {
      console.log(error);
    }
  };

弹簧

log

2024-07-14 02:10:54 2024-07-13T21:10:54.069Z  WARN 1 --- [nio-3001-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required part 'advertisement' is not present.]

backend

@PostMapping(value = "/create", consumes = "multipart/form-data")
    public ResponseEntity<?> saveAdvertisement(@RequestPart("advertisement") AdvertisementDTO aDto,
            @RequestPart("files") List<MultipartFile> files) {
        return facade.saveAdvertisement(aDto, files);
    }

public ResponseEntity<?> saveAdvertisement(AdvertisementDTO aDto,
            List<MultipartFile> files) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        User currentUser = (User) authentication.getPrincipal();
        Advertisement advertisement = Advertisement.builder()
                .title(aDto.getTitle())
                .description(aDto.getDescription())
                .category(catService.findById(aDto.getCategory().getCategory_id()))
                .user(currentUser)
                .price(aDto.getPrice())
                .date(LocalDateTime.now())
                .views(0L)
                .build();
        String result = iService.validateAndSaveImages(files);
        if (result != null)
            return ResponseEntity.badRequest().body(result);
        advertisement.setImages(files);

        try {
            service.save(advertisement);
            return ResponseEntity.ok().body("{\"status\":\"SUCCESS\"}");

        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("Advertisement creation failed: " + e.getMessage());
        }
    }

request body

      query: (newAdd) => {
        return {
          url: "/api/secured/create",
          method: "POST",
          body: newAdd,
        };
      },
      invalidatesTags: [{ type: "Advertisements", id: "LIST" }],
    }),

payload JSON

{
"_parts":
[
  ["advertisement",{"_data":{"blobId":"923737fc-8e5d-43d9-adec-af0fb0ff933d","offset":0,"size":80,"type":"application/json","__collector":{}}}],
  ["files",{"uri":"file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FCoreComponent-b964cf2e-b055-4d78-9e16-7ff1dbf5bec4/ImagePicker/83bd2379-6703-4a54-8764-e5427389de54.png","type":"image/jpeg","name":"profile.jpg"}]
]
}

P.S:事实上,React 上的 Web 应用程序可以正常工作(大部分是相同的代码),但是在移动设备上,当涉及到多部分时,它却不能正常工作

spring react-native image multipart
1个回答
0
投票

据我了解,你无法像在 React JS 中那样在 React Native 中发送 blob 文件,所以我必须添加这些代码行,这解决了问题:

const createBlob = (data) => {
    return new Blob([JSON.stringify(data)], { type: "application/json" });
  };
  const saveBlobToFile = async (blob) => {
    const base64Data = await blobToBase64(blob);
    const fileUri = FileSystem.documentDirectory + "advertisement.json";
    await FileSystem.writeAsStringAsync(fileUri, base64Data, {
      encoding: FileSystem.EncodingType.Base64,
    });
    return fileUri;
  };

  // Helper function to convert blob to base64
  const blobToBase64 = (blob) => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onloadend = () => {
        resolve(reader.result.split(",")[1]);
      };
      reader.onerror = reject;
      reader.readAsDataURL(blob);
    });
  };

最终结果如下所示:

const handlePost = async () => {
    const formDataToSend = new FormData();
    const token = await AsyncStorage.getItem("authToken");
    const advertisementBlob = createBlob(formData);
    const advertisementUri = await saveBlobToFile(advertisementBlob);
    formDataToSend.append("advertisement", {
      uri: advertisementUri,
      name: "advertisement.json",
      type: "application/json",
    });

    for (const uri of imageUris) {
      const fileUri = uri.replace("file://", "");
      const fileName = fileUri.split("/").pop();
      const fileType = fileName.endsWith(".png") ? "image/png" : "image/jpeg";
      formDataToSend.append("files", {
        uri: uri,
        type: fileType,
        name: fileName,
      });
    }

    try {
      const result = await axios.post(
        "http://<my_api>:3001/api/secured/create",
        formDataToSend,
        {
          headers: {
            Authorization: `Bearer ${token}`,
            "Content-Type": "multipart/form-data",
          },
          transformRequest: (d) => d,
        }
      );
      console.log(result);
    } catch (error) {
      console.log(JSON.stringify(error.request._response));
    }
  };

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