我被困在这里了。我不知道我做错了什么。我正在尝试将文件从 expo-image-picker 组件 发送到服务器。表格已发送,但图像未发送。
fetch
命令立即给出“网络请求失败”错误。服务器确实收到了请求,但没有附加图像。
更多信息:
我正在创建表单数据对象并将 blob 附加到其中。我也尝试过用
FormData.append("image", {uri, name: 'filename', type: 'image/filetype'})
来做这件事,大多数文章建议的方式,忽略 TS 错误,但它也失败了。
我没有提交给AWS或Firebase,所以我没有使用这些库,无论如何我看不出他们在做什么与我有什么不同。
我没有为此设置任何特定权限。我确实看到一些文章谈论上传权限,但它们已经超过 5 年了,并且谈论的是 android 5.0 之前的内容。
这是我用来提交的函数。
pathToImage
从 ImagePicker 返回。
const fetchImageFromUri = async (uri: string) => {
try {
const response = await fetch(uri);
const blob = await response.blob();
return blob;
} catch (error) {
console.log("fetchImageFromUri error:", error);
throw new Error("fetchImageFromUri");
}
};
const upload = async () => {
setMessage("");
setErrMessage("");
if (pathToImage != null) {
const fileToUpload = await fetchImageFromUri(pathToImage);
const formData = new FormData();
formData.append("action", "Image Upload");
formData.append("image", fileToUpload, "filename");
// from: https://stackoverflow.com/questions/71198201/react-native-unable-to-upload-file-to-server-network-request-failed
// most articles say this is the way to upload the file... Typescript gives an error
// because it only wants type 'string | Blob'
// let uriParts = pathToImage.split(".");
// let fileType = uriParts[uriParts.length - 1];
// formData.append("image", {
// uri: pathToImage,
// name: `photo.${fileType}`,
// type: `image/${fileType}`,
// });
// create the header options
const options: RequestInit = {
method: "POST",
body: formData,
headers: {
"Content-Type": "multipart/form-data",
Accept: "image/jpeg, image/png",
},
};
try {
const res = await fetch(URL, options);
console.log("fetch returned"); // this line is never reached
if (!res.ok) {
throw new Error("Something went wrong");
}
const body = (await res.json()) as any;
if (body.code > 200) {
setErrMessage(body.msg);
} else {
setMessage(body.msg);
}
} catch (err: any) {
setErrMessage("There was an error in upload");
console.log("upload catch error:", err.message);
}
}
};
完整代码可以在我的 GitHub 存储库中找到。
感谢 Brandonjgs 为我指明了正确的方向。我能够解决这个问题。
这是新的上传功能。
const upload = async () => {
console.log("\n***** Upload Image *****");
setMessage("");
setErrMessage("");
setLoading(true);
if (pathToImage) {
console.log("***** get other fields section *****");
const dataToSend: Record<string, string> = {};
dataToSend["action"] = "Image Upload";
console.log("***** Options section *****");
const options: FileSystemUploadOptions = {
headers: {
"Content-Type": "multipart/form-data",
Accept: "image/jpeg, image/png",
},
httpMethod: "POST",
uploadType: FileSystemUploadType.MULTIPART,
fieldName: "image",
parameters: dataToSend,
};
console.log("***** 'Fetch' section *****");
try {
const response = await FileSystem.uploadAsync(
URL,
pathToImage,
options
);
setLoading(false);
if (response.status >= 200 && response.status < 300) {
const body = JSON.parse(response.body);
setMessage(body.msg);
} else {
setErrMessage(`${response.status} Error: ${response.body}`);
}
} catch (err: any) {
console.error(err);
setErrMessage(err.message);
}
}
};
请务必查看 FileSystem.uploadAsync 文档。它不返回标准的 http 响应,它会格式化自己的响应并仅返回:
status
:错误代码header
:服务器返回的http headerbody
:无论服务器“发送”回来什么——在我的例子中它是 JSON。请注意,如果服务器没有响应或者它是一个错误的 URL,它会返回一个 HTML 错误页面,而不是一个标准错误消息字符串(我发现这是一个奇怪的选择,因为这是本地反应,我不一定导航到新的当我上传页面时,我捕获状态对象中的字符串以发布响应)。我也有同样的错误。这是我的代码,我总是得到 403 fordden
export const pickImage = async () => {
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== "granted") {
alert("Permission to access media library is required!");
return;
}
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
base64:true
});
if (!result.canceled) {
const uri = result.assets[0].uri;
const fileName = uri.split('/').pop();
const fileType = mime.getType(uri) || "image/jpeg";
if (Platform.OS === 'web') {
// Conversion en Blob pour le web */
const response = await fetch(uri);
const blob = await response.blob();
file = new File([blob], fileName, { type: fileType });
} else {
/* {
uri:
Platform.OS === "android"
? pickedImage.uri
: pickedImage.uri.replace("file://", ""),
name: "tata.jpeg",
type: "image/jpeg",
} */
// Utilisation de l'URI directement pour le mobile
file = {
uri: Platform.OS === "android" ? uri
: uri.replace("file://", ""),
name: fileName,
type: fileType,
};
console.log(file);
/* console.log("voire ",file.name) */
}
return {
response: file,
error: null,
};
}
return null;
};