Why MongoDB adding extra slash to path? - node.js

Good evening for everyone, I have some trouble with saving my url to mongodb database as string. Because mongo adding extra slash to every part of url. Like this:
"localhost:3333\uploads\Untitled1.cpp"
but in my console log I have normal result(look at the terminal in the screenshot). Whyy? Please, help
let storage = multer.diskStorage({
destination: (req, file, cb) =>{
cb(null, '/uploads')
},
filename: (req, file, cb) => {
cb(null, file.originalname)
}
})
let upload = multer({ storage: storage })
let type = upload.single('myFile');
app.post('/upload', type, (req, res) => {
const url = `http://localhost:3333${req.file.path}`;
const image = {
name: req.file.originalname,
url: url
}
console.log(image.url)
const newImage = new Image(image);
newImage.save()
.then (res.json('Картинку додано'))
.catch(err => res.status(400).json(err));
});

I assume you're using a Windows operating system which uses back slashes '\' for paths in its filesystem. The web (and Linux-based operating systems) use forward slashes '/' for paths. Therefore ${req.file.path}, which I'm guessing is referencing a file on your computer, is returning a path including back slashes.
You can use String.replace() with a regular expression to replace the back slashes with forward slashes:
let webPath = req.file.path.replace(/\\/g,'/'))
const url = `http://localhost:3333${webPath}`;

I have found the solution. What you need to do is when you are posting/saving your file into db there you need to use replace function and then your path will be saved with forward slash into your DB.
Here is the snippet:
app.post('/upload', upload.single('file'), (req, res, next) => {
const file = new Cluster1({
filePath: req.file.path.replace(/\\/g, '/'),
name: req.file.originalname
});
file.save()
You can see how I am using the replace fucntion to avoid \\ or \

Related

How to upload images to GCS bucket with multer and NodeJS?

I'm facing issues for uploading local images to my google cloud storage.
I've already tried two methods. The first one is uploading with multer
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './uploads/')
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now())
}
});
var upload = multer({storage: storage}).single('image');
app.post('/upload',function(req,res,next){
upload(req,res,(err) => {
if(err){
console.log(err)
}else{
console.log(req.file)
}
})
})
Then, i've tried directly with GCS
var bucket = admin.storage().bucket('mybucket')
app.post('/upload',function(req,res,next){
bucket
.save(file)
.then(() => {
})
for both of these solutions , req.files is always undefined whereas req.body is a buffer like this :
<Buffer 2d 2d 2d 2d ...>
when i try to save this buffer on my GCS bucket, i the .jpg/png file is created in my bucket but it is corrupted.
I'm browsing the web seeking for a solution but i found nothing that helped me to overcome this situation.
Any advice ?
You need multer, multer-google-storage and ofcourse bodyParser if you have additional form values. You need to sent data in multipart/form-data
In your .env file
GCS_BUCKET = <bucket name>
GCLOUD_PROJECT = <project id>
GCS_KEYFILE = <key file location>
You can download key file from GCP Console>Your Project>I AM & Admin>Service Accounts
In your route
const multer = require('multer');
const multerGoogleStorage = require("multer-google-storage");
var uploadHandler = multer({
storage: multerGoogleStorage.storageEngine()
});
router.post('/', uploadHandler.single('image'), function (req, res, next) {
const body = req.body;
res.json({fileName: req.file.filename});
res.end();
}
This will store file on to GCS with name [random-string-generated-by-gcs]_[YOUR FILE NAME WITH EXTENTION]. The same can be access under the route via req.file.filename.
Documentation
Make sure you have added enctype="multipart/form-data" attribute to your form. A probable reason for req.files being undefined.

Multer isn't saving to specified destination

I'm fairly new to nodejs/ express, but no matter what I seem to do I cant seem to get multer to save to the specified destination, it seems to completely ignore the parameter all together. The code is shown below
//app.js
var multer = require('multer');
var fs = require('fs');
var apiRouter = express.Router();
var app = express();
var store = multer.diskStorage({
filename: function(req,file,cb){
console.log("filename");
cb(null, Date.now()+'.'+file.originalname);
},
desitnation: function(req,file,cb){
console.log("storage");
cb(null,'./public/');
}
});
var upload = multer({storage:store}).single('file');
apiRouter.post('/upload', function(req, res){
upload(req, res, function (err) {
if (err) {
return res.end(err.toString());
}
console.log(req.file);
return res.json({originalname:req.file.originalname, uploadname:req.file.filename});
});
});
The response I get when uploading is shown below:
GET /vendor.js.map 200 3.916 ms - 6636755
filename
{ fieldname: 'file',
originalname: 'Desert.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: 'C:\\Users\\Dwyer\\AppData\\Local\\Temp',
filename: '1538979138829.Desert.jpg',
path:
'C:\\Users\\Dwyer\\AppData\\Local\\Temp\\1538979138829.Desert.jpg',
size: 845941 }
POST /api/upload 200 70.031 ms - 69
It seems to be setting the file correctly, but I'm not sure where it gets the destination from, no3 do I understand why the destination parameter isn't being read.
Its actually "destination" (not desitnation). You should also make sure that you have a folder ,with the specified name, at the specified destination.
Do you try using physical address in destination? I guess destination in multer document is physical address in linux os.
but no matter what I seem to do I cant seem to get multer to save to the specified destination, it seems to completely ignore the parameter all together.
This is because there seem to be a typo in the configuration.
'use strict';
var store = multer.diskStorage({
filename: function (req, file, cb) {
console.log("filename");
cb(null, Date.now() + '.' + file.originalname);
},
destination: function (req, file, cb) { // it is destination not desitnation :)
console.log("storage");
cb(null, './public/');
}
});

Multiple File Upload and rename by multer in node.js

I intended to use multer to upload multiple file and then rename them back to their original names. The below are the sample code:
var express = require('express');
var app = express();
var fs = require("fs");
var multer = require('multer');
app.use(express.static('public'));
var upload = multer({ dest: './upload/' });
app.get('/index.html', function (req, res) {
res.sendFile(__dirname + "/" + "index.html");
})
app.post('/file_upload', upload.array('theFile', 2), function (req, res, next) {
var errorcode = 0;
for (var i = 0; i < req.files.length; i++) {
fs.rename(req.files[i].path, req.files[i].destination + req.files[i].originalname, function (err) {
errorcode = err;
}(i));
}
if (errorcode != 0) {
console.log("errorcode is " + errorcode);
res.sendStatus(500);
return;
} else {
res.json({
message: 'File uploaded successfully',
});
}
})
var server = app.listen(8089, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
I'm testing the above code on a windows server. And my observation is that the files can be uploaded successfully but the fs.rename() keeps returning error "1". And the renamed files in the targeted folder are always 1Kb. It seems that the rename function intends to fetch the files which might be still uploading. I'm not sure whether my understanding is correct. If so, is there a way to determine whether the files have been uploaded completely? Any suggestion for my problem?
Why not use Multer's built-in renaming functionality?
Adapted from the documentation:
var storage = multer.diskStorage({
destination: '/path/to/uploads/folder',
filename: function (req, file, cb) {
// Here we specify the file name to save it as
cb(null, file.originalname);
}
})
// And we can use it for example like this:
app.post('/upload', upload.single('image'), function (req, res, next) {
// req.file is the `image` file
// req.body will hold the text fields, if there were any
})
However, there are a couple things you should be aware of if you take this approach:
The client can send any type of file, with any (potentially incorrect) extension. This is a potential security risk.
If two files are uploaded with the same name, the second file will overwrite the first.
If you serve these files to other users, the security risk greatly increases. An attacker could create a script or HTML page and upload it, possibly giving it a different file name extension. There are several ways it could be run, such as if the user tries to open it in a new tab because an image didn't show up. The full implications of this, and how to deal with it, are a topic of their own.
Finally, make very, very, sure that the user cannot write to a directory other than the uploads folder. What happens when file.originalname is something like ../../index.js? It may be better to convert the file name to a slug.

Node+Express pipe file directly to writeStream

In terms of learning i need to make a file uploading by myself with fs.streams
router.post('/upload', (req, res, next) => {
req.pipe(fs.createWritableStream('files/file.png'))
.on('error', (err) => next(err))
.on('close', () => {
res.json({image: 'files/file.png'});
})
})
This is dosen't work. So two questions
How to get file name and data from req?
How to connect this two streams?
Update: In all tutorials described opposite action - read file from fs and pipe it to res to enduser.
you can use multer
const multer = require('multer');
const upload = multer({
dest: 'folderName'
});
router.post('/upload', upload.single('formField'), (req, res, next) => {
res.json({image: req.file.path});
})
in this code file path will be sent.
if you want to send file itself, then you should write:
res.download(req.file.path);
instead of res.json({image: req.file.path}).
I don't know how res.download works exactly. maybe it takes whole buffer of the file and sends it.
multer's documentation is here

Renaming files using multer

I have configured multer as;
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, '../images/profile');
},
filename: function(req, file, cb) {
cb(null, req.body.username + '.jpeg'); // file does not get renamed
}
});
var upload = multer({storage: storage});
// Route that uses multer
router.post('/auth/signup/upload', upload.single('image'), function(req, res) {
console.log(req.body.username); // contains value
res.send();
});
Although req.body.username has a value, the file does not get renamed.
Wht am i missing here ?
From the multer manual:
Note that req.body might not have been fully populated yet. It depends on the order that the client transmits fields and files to the server.
Sadly, I don't believe there's a nice way to solve this. You could try switching the order of the fields in your HTML form, but this probably won't lead to consistent behaviours across browsers. You could also send the username on the query string instead (i.e. POST the file to http://foo.bar?username=me). You could also manually move the file afterwards, or store the mappings between usernames and files elsewhere.

Resources