Reputation: 524
EDIT: Figured out the issue, solution below.
I'm using multer and multer google storage to try to upload image files to my Google Cloud Bucket, but for some reason the files aren't being saved into the Google Cloud Bucket, and I can't log any errors, not sure what I'm doing wrong here. (Have tried to follow several different tutorials, read documentation, check other SO questions, etc. Still no solution).
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const passport = require('passport');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const multer = require('multer');
const path = require('path');
const multerGoogleStorage = require('multer-google-storage');
const { Storage } = require('@google-cloud/storage');
const gc = new Storage({
projectId: '{projectIdRedacted}',
keyFilename: path.join(__dirname, '../{keyFileNameRedacted.json}')
});
gc.getBuckets().then(x => console.log(x));
// This is showing that I've successfully paired to the Google Cloud bucket.
const bucket = gc.bucket('{redactedBucketNameHere}');
const fileFilter = (req, file, cb) => {
// Reject a file
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(null, false);
}
};
var uploadHandler = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 1024 * 1024 * 1
},
fileFilter: fileFilter
});
// Testing GCP Bucket Image Upload
// @route POST image-upload
// @desc Add image
// @access Private
router.post('/image-upload', uploadHandler.single('UploadBox'), passport.authenticate('jwt', {
session: false
}), (req, res, next) => {
// This is showing the req.file is being passed through
console.log(req.file);
const blob = bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream({
metadata: {
contentType: req.file.mimetype
},
resumable: false
});
// The err is not getting console logged even though it is not saving to the google cloud bucket properly?
blobStream.on('error', err => {
next(err);
console.log(err);
return;
})
// The publicUrl is not getting console.logged - presumably cause something is breaking before this and it won't save it
blobStream.on('finish', () => {
// the public url can be used to directly access the file via HTTP
const publicUrl = `https://storage.googleapis.com/${bucket.name}/${blob.name}`;
console.log(publicUrl);
// Make the image public to the web (since we'll be displaying it in the browser)
blob.makePublic().then(() => {
res.status(200).send(`Success!\n Image uploaded to ${publicUrl}`);
})
})
});
The documentation for @google-cloud/storage is: https://www.npmjs.com/package/@google-cloud/storage The documentation for multer google storage is: https://www.npmjs.com/package/multer-google-storage The documentation for Google's guide on using their cloud storage is: https://cloud.google.com/appengine/docs/flexible/nodejs/using-cloud-storage
Any tips and help would be greatly appreciated.
EDIT: I figured out the solution. I had to move up the uploadHandler and the fileFilter ABOVE the const { storage} import. And then inside the route, I had to add "blobStream.end();" after the blobStream.on('finish'). After doing so it resolved it. I've edited the working code below.
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const passport = require('passport');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const multer = require('multer');
const path = require('path');
const multerGoogleStorage = require('multer-google-storage');
const fileFilter = (req, file, cb) => {
// Reject a file
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(null, false);
}
};
var uploadHandler = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 1024 * 1024 * 1
},
fileFilter: fileFilter
});
const { Storage } = require('@google-cloud/storage');
const gc = new Storage({
projectId: '{projectIdRedacted}',
keyFilename: path.join(__dirname, '../{keyFileNameRedacted.json}')
});
gc.getBuckets().then(x => console.log(x));
const bucket = gc.bucket('{bucketNameRedacted}');
// Testing GCP Bucket Image Upload
// @route POST image-upload
// @desc Add image
// @access Private
router.post('/image-upload', uploadHandler.single('UploadBox'), passport.authenticate('jwt', {
session: false
}), (req, res, next) => {
// This is showing the req.file is being passed through
console.log(req.file);
const blob = bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream({
metadata: {
contentType: req.file.mimetype
},
resumable: false
});
// The err is not getting console logged even though it is not saving to the google cloud bucket properly?
blobStream.on('error', err => {
next(err);
console.log(err);
return;
})
// The publicUrl is not getting console.logged - presumably cause something is breaking before this and it won't save it
blobStream.on('finish', () => {
// the public url can be used to directly access the file via HTTP
const publicUrl = `https://storage.googleapis.com/${bucket.name}/${blob.name}`;
console.log(publicUrl);
// Make the image public to the web (since we'll be displaying it in the browser)
blob.makePublic().then(() => {
res.status(200).send(`Success!\n Image uploaded to ${publicUrl}`);
})
})
blobStream.end();
});
Upvotes: 0
Views: 2341
Reputation: 524
I figured out the solution. I had to move up the uploadHandler and the fileFilter ABOVE the const { storage} import. And then inside the route, I had to add "blobStream.end();" after the blobStream.on('finish'). After doing so it resolved it. I've edited the working code below.
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const passport = require('passport');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const multer = require('multer');
const path = require('path');
const multerGoogleStorage = require('multer-google-storage');
const fileFilter = (req, file, cb) => {
// Reject a file
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(null, false);
}
};
var uploadHandler = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 1024 * 1024 * 1
},
fileFilter: fileFilter
});
const { Storage } = require('@google-cloud/storage');
const gc = new Storage({
projectId: '{projectIdRedacted}',
keyFilename: path.join(__dirname, '../{keyFileNameRedacted.json}')
});
gc.getBuckets().then(x => console.log(x));
const bucket = gc.bucket('{bucketNameRedacted}');
// Testing GCP Bucket Image Upload
// @route POST image-upload
// @desc Add image
// @access Private
router.post('/image-upload', uploadHandler.single('UploadBox'), passport.authenticate('jwt', {
session: false
}), (req, res, next) => {
// This is showing the req.file is being passed through
console.log(req.file);
const blob = bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream({
metadata: {
contentType: req.file.mimetype
},
resumable: false
});
// The err is not getting console logged even though it is not saving to the google cloud bucket properly?
blobStream.on('error', err => {
next(err);
console.log(err);
return;
})
// The publicUrl is not getting console.logged - presumably cause something is breaking before this and it won't save it
blobStream.on('finish', () => {
// the public url can be used to directly access the file via HTTP
const publicUrl = `https://storage.googleapis.com/${bucket.name}/${blob.name}`;
console.log(publicUrl);
// Make the image public to the web (since we'll be displaying it in the browser)
blob.makePublic().then(() => {
res.status(200).send(`Success!\n Image uploaded to ${publicUrl}`);
})
})
blobStream.end();
});
Upvotes: 0
Reputation: 624
You don't really need the multer-google-storage
package, that's by the way.
kindly comment the response error message you get when you hit the route meant for this upload.
Upvotes: 1