我目前正在构建一个React JS应用程序,该应用程序与我同时使用Node JS构建的API进行通信,并且我遇到了上传图像并正确显示的问题。我推测问题源于应用程序如何处理上传图像。
用户通过以下形式上传头像:
<form
id="RegistrationForm"
ref={FormRef}
encType="multipart/form-data"
className={`bg-[#f2e798] w-11/12 md:w-9/12 mx-auto lg:w-6/12 mt-[20px] py-10 rounded box_shadow`}
onSubmit={(evt) => {
evt.preventDefault();
const ImageInputElem = ImageInputRef.current;
UploadNewProfilePic(uploadURL, ImageInputElem, setPictureError)
}}
>
<div className= "FormStyle w-11/12 mx-auto grid">
<label htmlFor="profile_pic">Profile picture</label>
<input
name="profile_pic"
id="profile_picInput"
ref={ImageInputRef}
type="file"
placeholder="Upload an image htmlFor your your profile picture here"
className="text-lg file:rounded-lg file:font-['DecoTech'] file:bg-[#99cbae] file:text-white cursor-pointer border-black border-[1px] rounded"
onChange={(evt) => { HandleFileChange(evt, setImage) }}
/>
<FormButtons />
</div>
<div
id="pictureError"
className="ErrorDiv"
ref={ImageErrorRef}>
{pictureError != null && pictureError.length > 0 && RenderError(pictureError)}
</div>
</form>
下面的钩子用于在用户提交表单时将fetch请求发送到服务器:
const UploadNewProfilePic = async (apiURL, ImageInputElem, setPictureError) => {
const formData = new FormData;
formData.append("profile_pic", ImageInputElem.files[0])
try {
await fetch(apiURL,
{
method: "PUT",
body: formData,
}
)
.then(async response => {
const result = await response.json();
if (response.ok) {
console.log("Uploaded image successfully: ", result.message)
GoHome();
}
else {
console.log("Upload failed: ", result.error)
RenderErrorArray(result.error, setPictureError);
}
})
} catch (e) {
console.log("Error uploading file:", error);
RenderErrorArray([{ para: "file upload error", msg: `Upload error: ${error}` }], setPictureError);
}
}
在服务器端,路由设置如下:
const express = require('express');
const router = express.Router();
const cors = require('cors');
const UserController = require('../controller/userController.js');
const path = require('path')
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "public/uploads")
},
filename: function (req, file, cb) {
const ext = path.extname(file.originalname);
const filename = `${Date.now()}-${file.filename}${ext}`;
cb(null, filename)
},
});
const upload = multer({
limits: { fileSize: 1024 * 1024 * 5 },
storage: storage,
fileFilter: function (req, file, cb) {
if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) {
return cb(new Error('Only image files are allowed!'));
}
cb(null, true);
}
});
router.put('/users/:id/uploadnewpicture', cors(), upload.single("profile_pic"), UserController.UploadNewProfilePicture)
上传图片的存储类型为buffer类型:
const User = new Schema({
//...
profile_pic: { data: Buffer, contentType: String },
//...
})
以下控制器函数用于处理PUT请求:
exports.UploadNewProfilePicture = (req, res, next) => {
try {
const { BufferImage } = dataHooks();
const BufferedImg = {
data: fs.readFileSync(path.join(__dirname, '../public/uploads/', req.file.filename)),
contentType: req.file.mimetype,
}
const updates = {
_id: req.params.id,
profile_pic: BufferedImg,
}
const updateUser = new User(updates)
User.findByIdAndUpdate(req.params.id, updateUser)
.then(() => {
return res.status(200).json({message: "Profile picture has been successfully updates."})
})
.catch(e => {
return res.status(404).json({ error: [{ param: "server", msg: `Error in updating profile picture: ${e}.` }] })
})
} catch (e) {
console.log("Error in uploading new profile picture: ", e)
return res.status(500).json({ error: [{para: "server error", msg: `Upload error: ${e}`}]})
}
}
然后,回到客户端,当应用呈现呈现配置文件图像的页面时,它执行以下钩子从服务器检索图像:
const FetchProfilePic = async (apiURL, userID, dispatch) => {
await fetch(apiURL,
{
method: "GET",
}
)
.then(async response => {
if (response.ok) {
await response.json()
.then(result => {
localStorage.setItem("ProfilePicture", JSON.stringify(result.profile_pic))
dispatch(result.profile_pic)
})
}
else {
const result = await response.json();
console.log("Error in fetching image: ", result.error)
}
})
}
最后,它使用以下钩子来渲染配置文件图像:
const RenderProfilePic = props => {
const { profile_pic } = props;
const ImageStyle = `select-none w-[270px] h-[270px] object-cover rounded-full mx-auto`;
const ImageWrapperStyle = `m-auto overflow-hidden relative z-[1]`;
console.log("profile_pic: ", typeof profile_pic.data)
const binaryData = new Uint8Array(profile_pic.data);
const base64Image = btoa(String.fromCharCode.apply(null, binaryData));
//const base64Image = profile_pic.data.toString('base64');
const dataURL = `data:${profile_pic.contentType};base64,${base64Image}`;
try {
return (
<div
id="ImageWrapper"
className={ImageWrapperStyle}
>
<img src={dataURL} alt="Profile Picture" className={`${ImageStyle}`} />
</div>
)
} catch (e) {
console.log("error in rendering image: ", e)
}
}
我注意到的是,每当客户端从服务器检索图像时,图像的类型都是作为对象而不是类型缓冲区。
console.log(typeof profile_pic) // returns object
如果在座的任何人能给予我一些关于如何解决这个问题的指导,我将不胜感激。
Github for client site
Github for server site
1条答案
按热度按时间uqxowvwt1#
最后,我在别人的帮助下解决了这个问题。
问题是缓冲区的数据不能在Node外部解释,所以需要先转换为base64。
我实现了以下函数:
当应用程序从服务器接收到缓冲区数据并将其转换为base64时,它会触发。