在 MERN 堆栈 Web 应用程序中存储图像的最佳方式
Posted
技术标签:
【中文标题】在 MERN 堆栈 Web 应用程序中存储图像的最佳方式【英文标题】:Best way to store images in MERN stack web application 【发布时间】:2020-10-02 20:37:58 【问题描述】:我正在使用 MERN 堆栈(MongoDB、Express Server、ReactJS 前端和 NodeJS 后端)构建一个 Web 应用程序,并且想知道一些从后端存储图像的好方法。
过去,我直接从前端使用 Firebase 进行身份验证和存储。当我在 MongoDB 中处理我自己的用户身份验证模型时,是否仍然可以使用 firebase 存储,如果可以,它会来自前端还是后端。如果它来自前端,我如何在没有 Firebase 身份验证的情况下保护它?
我读过的其他选项是使用 GridFS 将图像存储到 MongoDB 或使用 Multer 存储在服务器上。
一旦我想到了一个解决方案,我就可以阅读文档并弄清楚如何完成它。
感谢任何建议。
【问题讨论】:
【参考方案1】:您可以通过[实现自定义提供程序](后者为https://firebase.google.com/docs/auth/web/custom-auth)将任何外部身份验证系统连接到 Firebase 身份验证。
这要求您在受信任的环境中运行代码,例如您控制的服务器或 Cloud Functions,您可以在其中获取用户的身份验证结果并将其转换为 Firebase 身份验证令牌。
然后,客户端使用该令牌登录 Firebase,从那一刻起,存储(和其他服务)就像以前一样了解用户。
【讨论】:
【参考方案2】:一个选项是将图像上传到客户端的Cloudinary,然后使用您自己的 API 将返回的 URL 保存到 MongoDB。 Cloudinary 不仅可以托管您的图像,还可以处理图像操作和优化等等。
基本上你要做的是:
-
注册 Cloudinary 帐户
进入设置 -> 上传
使用“未签名模式”添加“上传预设”以启用未签名上传到 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
【讨论】:
嘿@Hangindev,这正是我想做的,但我仍然是超级新的 MERN 和 Cloudinary。你介意帮我解决这个问题吗?我只是不能 100% 确定一切都应该去哪里jsfiddle.net/qfme5h8k 嗨@FrazerFindlater,你可以看看我整理的这个codesandbox。【参考方案3】:我认为使用 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
);
【讨论】:
【参考方案4】:我最终从 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' );
);
认为如果将来有人偶然发现这篇文章,这可能会有所帮助。
【讨论】:
以上是关于在 MERN 堆栈 Web 应用程序中存储图像的最佳方式的主要内容,如果未能解决你的问题,请参考以下文章
当同时使用 GraphQL 时,Nodejs 和 Express 在 MERN 堆栈 Web 应用程序中的作用是啥?
即使设置了 sameSite:'none' 和 secure: true 对于 MERN 堆栈 Web 应用程序,Cookie 也不会保存在 chrome 中