当我尝试将图像文件(缓冲区)上传到 Cloudinary 时,我的代码中出现一些错误。
const cloudinary = require("cloudinary").v2;
但是当我将图像存储在 MongoDB 数据库中时,它存储得很好。我创建了一个用户注册流程。当用户输入信息并尝试注册时,将生成一个令牌并将其存储在数据库中。但在将用户信息存储到数据库之前,我想将用户图像文件存储到 Cloudinary 并将其 URL 存储到数据库中。当我尝试这样做时,我收到错误。这是我的代码...
const image = req.file;
if (!image) {
throw createHttpError(400, "Image file is required");
}
if (image) {
if (image.size > 1024 * 1024 * 2) {
throw createHttpError(
400,
"File is too large. It must be less than 2 MB"
);
}
}
// buffer
const imageBufferString = req.file.buffer.toString("base64");
// create jwt
const tokenPayload = {
username,
email,
password,
phone,
address,
image: imageBufferString,
};
const token = createJSONWebToken(tokenPayload, jwtActivisionKey, "10m");
try {
const token = req.body.token;
if (!token) throw createHttpError(404, "Token not found!");
try {
// verify user and register
const decoded = jwt.verify(token, jwtActivisionKey);
if (!decoded) throw createHttpError(401, "Unable to verify user");
// console.log(decoded);
const userExists = await User.exists({ email: decoded.email });
if (userExists) {
throw createHttpError(
409,
"User with this email already exists. Please login"
);
}
const image = decoded.image; // declaring image from the token
// if (image) {
// const uploadResult = cloudinary.uploader.upload_stream(
// image,
// { folder: "Mern" },
// function (error, result) {
// console.log(error, result);
// }
// );
// return streamifier.createReadStream(image).pipe(uploadResult);
// }
await new Promise((resolve) => {
const uploadResult = cloudinary.uploader
.upload_stream(
{ folder: "Mern", resource_type: "image" },
(error, result) => {
if (result) {
console.log(result);
return resolve(result);
}
console.log(error);
}
)
.end(image);
streamifier.createReadStream(image.buffer).pipe(uploadResult);
// decoded.image = uploadResult.secure_url;
});
// and then create user
const user = await User.create(decoded);
return successResponse(res, {
statusCode: 201,
message: "User was registered successfully",
payload: user,
});
} catch (error) {
if (error.name === "TokenExpiredError") {
throw createHttpError(401, "Token has expired");
} else if (error.name === "JsonWebTokenError") {
throw createHttpError(401, "Invalid Token");
} else {
throw error;
}
}
} catch (error) {
next(error);
console.log(error.message);
}
const multer = require("multer");
const MAX_FILE_SIZE = 2097152; // 2mb -- 1024bytes * 1024kb * 2
const ALLOWED_FILE_TYPES = ["image/jpg", "image/jpeg", "image/png"];
const UPLOAD_USER_IMG_DIR = "public/images/users";
// for user image
const userStorage = multer.memoryStorage();
const fileFilterUser = (req, file, cb) => {
if (!file.mimetype.startsWith("image/")) {
return cb(new Error("Only image files are allowed"), false);
}
if (file.size > MAX_FILE_SIZE) {
return cb(new Error("File size exceeds the maximum limit"), false);
}
if (!ALLOWED_FILE_TYPES.includes(file.mimetype)) {
return cb(new Error("File type is not allowed"), false);
}
cb(null, true);
};
const uploadUserImage = multer({
storage: userStorage,
fileFilter: fileFilterUser,
});
userRouter.post(
"/process-register",
uploadUserImage.single("image"),
isLoggedOut,
validateUserRegistration,
runValidation,
handleProcessRegister
);
userRouter.post("/activate", isLoggedOut, handleActivateUserAccount);
console.log 输出...
{ message: 'Invalid image file', name: 'Error', http_code: 400 }
当我更改代码时,控制台中出现了不同的错误......
TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer or Uint8Array. Received undefined
或 The "path" argument must be of type string or an instance of Buffer or URL. Received undefined
或 { message: 'empty file', name: 'error', http_code: 400 }
终于解决了错误...
我收到错误是因为我尝试将二进制图像直接编码到 JWT 中。当我尝试这样做时,二进制数据的有效负载变得更大。此外,从 JWT 和用户验证中解码二进制图像(JWT 无法解码精确的大二进制数据)也是一个问题。 JWT 不适合大负载。这不仅可能导致大小问题,还会导致解码和处理二进制数据时出现问题。 然后我应用了一些流程:
步骤:1
我。首先,将图像上传到Cloudinary。
// Utility function to upload to Cloudinary
const uploadToCloudinary = (bufferImage) => {
return new Promise((resolve, reject) => {
const stream = cloudinary.uploader.upload_stream(
{ resource_type: "image", visibility: "public" },
(error, result) => {
if (error) reject(error);
else resolve(result);
}
);
streamifier.createReadStream(bufferImage).pipe(stream);
});
};
module.exports = uploadToCloudinary;
ii.获取图像 URL:上传后,Cloudinary 会提供一个响应,其中包含上传图像的 URL。
*从 userController 上传图像...
const image = req.file;
if (!image) {
throw createHttpError(400, "Image file is required");
}
// buffer
const bufferImage = image.buffer;
// uploading image to cloudinary and collect its URL to encode it to the JWT
const result = await uploadToCloudinary(bufferImage);
if (!result || !result.secure_url) {
throw new Error("Failed to upload image to Cloudinary.");
}
const imageUrl = result.secure_url;
iii.然后在 JWT 中对图像 URL 进行编码(创建一个在其负载中包含图像 URL 的 JWT)。
// create jwt
const tokenPayload = {
username,
email,
password,
phone,
address,
image: imageUrl,
};
const token = createJSONWebToken(tokenPayload, jwtActivisionKey, "10m");
步骤:2 通过解码令牌并提取图像 URL 来解码 JWT 并处理用户验证。
// verify user and register
const decoded = jwt.verify(token, jwtActivisionKey);
if (!decoded) throw createHttpError(401, "Unable to verify user");
const imageUrl = decoded.image;
console.log(imageUrl);
// and then create user
const user = await User.create(decoded);