在 MERN 堆栈 Web 应用程序中存储图像的最佳方式
Best way to store images in MERN stack web application
我正在使用 MERN 堆栈(MongoDB、Express Server、ReactJS 前端和 NodeJS 后端)构建 Web 应用程序,想知道从后端存储图像的一些好方法。
以前都是直接在前端用Firebase做认证和存储。当我在 MongoDB 中处理我自己的用户身份验证模型时,是否仍然可以使用 firebase 存储,如果是的话,它是来自前端还是后端。如果它来自前端,我将如何在没有 firebase 身份验证的情况下保护它?
我读到的其他选项是使用 GridFS 将图像存储到 MongoDB 或使用 Multer 存储在服务器上。
一旦我想到了解决方案,我将能够阅读文档并弄清楚如何完成它。
如有任何建议,我们将不胜感激。
您可以通过[实施自定义提供程序](https://firebase.google.com/docs/auth/web/custom-auth 将任何外部身份验证系统连接到 Firebase 身份验证。
这需要您 运行 在受信任的环境中编写代码,例如您控制的服务器或 Cloud Functions,您可以在其中获取用户的身份验证结果并将其转换为 Firebase 身份验证令牌。
然后客户端使用该令牌登录 Firebase,从那时起,存储(和其他服务)就会像以前一样了解用户。
一个选项是在客户端上传图片到Cloudinary,然后用你自己的API保存返回的URL到MongoDB。 Cloudinary 不仅可以托管您的图像,还可以处理图像处理和优化等。
基本上您需要做的是:
- 注册 Cloudinary 帐户
- 转到设置 -> 上传
- 添加 "upload preset" 和 'Unsigned mode' 以启用未签名的上传到 Cloudinary
那么你的上传函数可以是这样的:
async function uploadImage(file) { // file from <input type="file">
const data = new FormData();
data.append("file", file);
data.append("upload_preset", NAME_OF_UPLOAD_PRESET);
const res = await fetch(
`https://api.cloudinary.com/v1_1/${YOUR_ID}/image/upload`,
{
method: "POST",
body: data,
}
);
const img = await res.json();
// Post `img.secure_url` to your server and save to MongoDB
}
我认为使用 multer 是非常方便的方法。
您可以使用 multer 将图像上传到文件夹中,并将参考 URL 存储在 MongoDB 中。如果您愿意托管您的 MERN 申请,这一点也很重要。您不需要任何第三方帮助,例如 firebase 或 Cloudinary 上传和身份验证(您已经这样做了)。
因此,您可以使用自己的功能托管自己的应用程序。无外部成本(仅用于域 :D)
这可能会帮助您获得一个简短的想法。
const InstrumentImageStore = multer.diskStorage({
destination: function (req, file, callback) {
const userId = req.userId;
const dir = `instrumentImgs/${userId}`;
fs.exists(dir, (exist) => {
if (!exist) {
return fs.mkdir(dir, (error) => callback(error, dir));
}
return callback(null, dir);
});
},
filename: function (req, file, callback) {
callback(null, Date.now() + "-" + file.originalname);
},
});
router.post(
"/add/instrument",
[isauth, multer({ storage: InstrumentImageStore }).array("imageArr", 5)],
//isauth is another middleware that restricts requests using JWT
instrumentController.addInstrument
);
我最终从 Firebase Admin SDK 实现了 Firebase 存储,并使用 Multer 将图像存储在内存中,直到我将它们加载到 Firebase。
https://firebase.google.com/docs/storage/admin/start
const uploader = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024,
},
});
// @route POST api/users/upload/avatar
// @desc Upload a new avatar and save to storage
// @access Private
router.post('/upload/avatar', [auth, uploader.single('image')], async (req, res, next) => {
if (!req.file) {
res.status(400).json({ msg: 'No file submitted.' });
return;
}
try {
const blob = firebase.bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream({
gzip: true,
resumable: false,
metadata: {
contentType: req.file.mimetype,
},
});
blobStream.on('error', (err) => next(err));
blobStream.on('finish', () => {
publicUrl = `https://firebasestorage.googleapis.com/v0/b/${
firebase.bucket.name
}/o/${encodeURI(blob.name)}?alt=media`;
res.status(200).json({
photoURL: publicUrl,
});
User.findById(req.user.id).then((user) => {
user.photoURL = publicUrl;
user.save();
});
});
blobStream.end(req.file.buffer);
} catch (error) {
console.error(error.message);
res.status(500).send({ msg: 'A Server error occurred' });
}
});
我认为这可能会对以后有人偶然发现这个 post 有所帮助。
我正在使用 MERN 堆栈(MongoDB、Express Server、ReactJS 前端和 NodeJS 后端)构建 Web 应用程序,想知道从后端存储图像的一些好方法。
以前都是直接在前端用Firebase做认证和存储。当我在 MongoDB 中处理我自己的用户身份验证模型时,是否仍然可以使用 firebase 存储,如果是的话,它是来自前端还是后端。如果它来自前端,我将如何在没有 firebase 身份验证的情况下保护它?
我读到的其他选项是使用 GridFS 将图像存储到 MongoDB 或使用 Multer 存储在服务器上。
一旦我想到了解决方案,我将能够阅读文档并弄清楚如何完成它。
如有任何建议,我们将不胜感激。
您可以通过[实施自定义提供程序](https://firebase.google.com/docs/auth/web/custom-auth 将任何外部身份验证系统连接到 Firebase 身份验证。
这需要您 运行 在受信任的环境中编写代码,例如您控制的服务器或 Cloud Functions,您可以在其中获取用户的身份验证结果并将其转换为 Firebase 身份验证令牌。
然后客户端使用该令牌登录 Firebase,从那时起,存储(和其他服务)就会像以前一样了解用户。
一个选项是在客户端上传图片到Cloudinary,然后用你自己的API保存返回的URL到MongoDB。 Cloudinary 不仅可以托管您的图像,还可以处理图像处理和优化等。
基本上您需要做的是:
- 注册 Cloudinary 帐户
- 转到设置 -> 上传
- 添加 "upload preset" 和 'Unsigned mode' 以启用未签名的上传到 Cloudinary
那么你的上传函数可以是这样的:
async function uploadImage(file) { // file from <input type="file">
const data = new FormData();
data.append("file", file);
data.append("upload_preset", NAME_OF_UPLOAD_PRESET);
const res = await fetch(
`https://api.cloudinary.com/v1_1/${YOUR_ID}/image/upload`,
{
method: "POST",
body: data,
}
);
const img = await res.json();
// Post `img.secure_url` to your server and save to MongoDB
}
我认为使用 multer 是非常方便的方法。
您可以使用 multer 将图像上传到文件夹中,并将参考 URL 存储在 MongoDB 中。如果您愿意托管您的 MERN 申请,这一点也很重要。您不需要任何第三方帮助,例如 firebase 或 Cloudinary 上传和身份验证(您已经这样做了)。
因此,您可以使用自己的功能托管自己的应用程序。无外部成本(仅用于域 :D)
这可能会帮助您获得一个简短的想法。
const InstrumentImageStore = multer.diskStorage({
destination: function (req, file, callback) {
const userId = req.userId;
const dir = `instrumentImgs/${userId}`;
fs.exists(dir, (exist) => {
if (!exist) {
return fs.mkdir(dir, (error) => callback(error, dir));
}
return callback(null, dir);
});
},
filename: function (req, file, callback) {
callback(null, Date.now() + "-" + file.originalname);
},
});
router.post(
"/add/instrument",
[isauth, multer({ storage: InstrumentImageStore }).array("imageArr", 5)],
//isauth is another middleware that restricts requests using JWT
instrumentController.addInstrument
);
我最终从 Firebase Admin SDK 实现了 Firebase 存储,并使用 Multer 将图像存储在内存中,直到我将它们加载到 Firebase。
https://firebase.google.com/docs/storage/admin/start
const uploader = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024,
},
});
// @route POST api/users/upload/avatar
// @desc Upload a new avatar and save to storage
// @access Private
router.post('/upload/avatar', [auth, uploader.single('image')], async (req, res, next) => {
if (!req.file) {
res.status(400).json({ msg: 'No file submitted.' });
return;
}
try {
const blob = firebase.bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream({
gzip: true,
resumable: false,
metadata: {
contentType: req.file.mimetype,
},
});
blobStream.on('error', (err) => next(err));
blobStream.on('finish', () => {
publicUrl = `https://firebasestorage.googleapis.com/v0/b/${
firebase.bucket.name
}/o/${encodeURI(blob.name)}?alt=media`;
res.status(200).json({
photoURL: publicUrl,
});
User.findById(req.user.id).then((user) => {
user.photoURL = publicUrl;
user.save();
});
});
blobStream.end(req.file.buffer);
} catch (error) {
console.error(error.message);
res.status(500).send({ msg: 'A Server error occurred' });
}
});
我认为这可能会对以后有人偶然发现这个 post 有所帮助。