无法发送带有图像的 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 应用程序可以正常工作(大部分是相同的代码),但是在移动设备上,当涉及到多部分时,它却不能正常工作
据我了解,你无法像在 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));
}
};